# Elio Proactive Wakeup API Target environment: `pro` pre-release. Base URL: ```text https://proapi.banlv-ai.com ``` All endpoints require: ```http X-Admin-Token: Content-Type: application/json ``` `ADMIN_VIEW_TOKEN` can only read rules. Updating rules or running scans requires `ADMIN_TOKEN`. ## Status The proactive wakeup scheduler is deployed on `pro`, but real sending is guarded by environment flags: ```text ENABLE_PROACTIVE_WAKEUP=false PROACTIVE_WAKEUP_DRY_RUN=true ``` With the current default, the hourly scheduler skips sending. The admin UI can still manually call dry-run for monitoring. ## Rule Model ```ts type ProactiveRule = { id: string; rule_key: | "global_anti_harassment" | "festival" | "social_post_share" | "dormant_wakeup"; category: "guardrail" | "festival" | "social_post" | "dormant"; enabled: boolean; priority: number; trigger_conditions: Record; behavior_strategy: Record; frequency_limit: Record; created_at: string; updated_at: string; }; ``` Default rules: | Rule | Purpose | Main Limits | | --- | --- | --- | | `festival` | Valentine, Christmas, birthday personalized wakeup | Max 1 per festival cycle | | `social_post_share` | Share Elio latest Facebook post | Max 1 per FB post event | | `dormant_wakeup` | 48h inactivity wakeup | Max 1 per dormant cycle | | `global_anti_harassment` | Stop waking users after 7 idle days | Global suppression | ## List Rules ```http GET /api/admin/proactive/rules ``` Example: ```bash curl -H "X-Admin-Token: $ADMIN_TOKEN" \ https://proapi.banlv-ai.com/api/admin/proactive/rules ``` Response: ```json { "success": true, "data": [ { "id": "8b14a3bf-6c01-4d0c-85b5-613399cb8f14", "rule_key": "dormant_wakeup", "category": "dormant", "enabled": true, "priority": 30, "trigger_conditions": { "min_idle_hours": 48, "min_user_messages": 5 }, "behavior_strategy": { "mode": "ai_dormant_wakeup", "tone": "soft_missing", "send_channel": "cozsweet" }, "frequency_limit": { "cycle_scope": "dormant_period", "max_per_cycle": 1 }, "created_at": "2026-06-29T07:38:46.155433+00:00", "updated_at": "2026-06-29T10:52:11.041169+00:00" } ] } ``` ## Update Rule ```http PATCH /api/admin/proactive/rules/{rule_key} ``` Allowed request fields: ```ts type UpdateProactiveRuleRequest = { enabled?: boolean; priority?: number; trigger_conditions?: Record; behavior_strategy?: Record; frequency_limit?: Record; }; ``` Example: ```bash curl -X PATCH \ -H "X-Admin-Token: $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"enabled":true}' \ https://proapi.banlv-ai.com/api/admin/proactive/rules/dormant_wakeup ``` Response: ```json { "success": true, "data": { "rule_key": "dormant_wakeup", "enabled": true, "priority": 30, "trigger_conditions": { "min_idle_hours": 48, "min_user_messages": 5 } } } ``` ## Run Scan ```http POST /api/admin/proactive/run?dry_run=true ``` Query parameters: | Name | Type | Default | Meaning | | --- | --- | --- | --- | | `dry_run` | boolean | `true` | `true` previews eligible candidates; `false` sends and writes delivery records only when `ENABLE_PROACTIVE_WAKEUP=true`. | Example: ```bash curl -X POST \ -H "X-Admin-Token: $ADMIN_TOKEN" \ "https://proapi.banlv-ai.com/api/admin/proactive/run?dry_run=true" ``` Current pro response with no eligible users: ```json { "success": true, "data": { "enabled": false, "dryRun": true, "candidates": 0, "sent": 0, "items": [] } } ``` When candidates exist, `items` contains rule/cycle context and, in dry-run mode, generated preview messages. ## Frontend States Handle these states in the admin UI: | State | How to detect | UI suggestion | | --- | --- | --- | | Unauthorized | HTTP `403`, `message=admin token required` | Ask operator to enter an admin token. | | No candidates | `success=true`, `data.candidates=0` | Show an empty state. | | Dry-run preview | `data.dryRun=true`, `items.length>0` | Show candidate list and preview text. | | Sending disabled | `data.enabled=false` | Display that real sending is off in environment config. | | Send executed | `data.dryRun=false`, `data.sent>0` | Show sent count and delivery rows. | | Partial failure | Any item with `status="failed"` | Show per-user failure reason and keep successful rows. | ## Notes - User eligibility requires cozsweet/web user messages `>= 5` and last interaction older than the rule threshold. - The global anti-harassment rule suppresses wakeups once the user has been idle for 7 days. - Birthday wakeups require birthday data. The migration includes `users.birthday`; if the column is not present yet, birthday matching is skipped without breaking other rules. - Facebook post sharing requires inserting an `elio_fb_post` row into `proactive_message_events`.