# SayWink > SayWink automates Instagram "comment a keyword → get a DM": when someone comments a keyword on the owner's post, SayWink replies publicly (optional), sends a private DM with a button, and delivers a link once the person taps or answers. It is built to be operated by AI assistants through a remote MCP server: one API key = one owner, who may have connected several Instagram professional accounts (up to their plan's limit); the key reaches all of them and nothing else. Links below are relative to the host serving this file (the SayWink app, `APP_URL`). ## Connect - MCP endpoint: `/mcp`. Transport: Streamable HTTP. Auth: header `Authorization: Bearer rpl_…`. The owner creates the key in the SayWink dashboard; it is shown once and reaches every Instagram account of that owner; the account it was created from is its default. OAuth sign-in isn't available yet. Clients that can't send a custom header (ChatGPT chat; Claude custom connectors without the Request headers beta) need a stdio bridge such as `npx mcp-remote /mcp --header "Authorization:${AUTH_HEADER}"`. - Claude Code: `claude mcp add --transport http --scope user replai /mcp --header "Authorization: Bearer rpl_…"` - The dashboard has a copy-paste snippet for each of these: Claude Desktop/claude.ai, Codex (`~/.codex/config.toml`: `url` + `bearer_token_env_var`), Cursor (`mcp.json`: `url` + `headers`), Gemini CLI (`httpUrl` + `headers`), VS Code (`servers` with `"type": "http"` + `headers`), Windsurf (`serverUrl` + `headers`). - MCP extras: the resource `replai://guide` (full guide) and the prompts `setup_giveaway_rule` and `review_performance`. ## Docs - [SayWink Agent Skill](/skill/replai/SKILL.md): workflow, rule fields, follow policy, DM copywriting, limits, troubleshooting. Install it as `~/.claude/skills/replai/SKILL.md`. - [Copy templates](/skill/replai/templates.md): ready rule drafts in English, Portuguese and Spanish. - [MCP endpoint](/mcp): POST JSON-RPC (Streamable HTTP) with the bearer header. ## Tools (16) Every tool except `list_accounts` takes an optional `account`: the Instagram username (with or without `@`) or `ig_user_id`. Omitted = the key's default account. An account the owner doesn't have is refused with the list of usernames the key can use. Every result names the account it acted on (`@username` in the text, `account` in the structured data). Rule ids and `media_id`s belong to one account. - `list_accounts`: the owner's accounts (`ig_user_id`, `username`, `name`, `subscribed`, `is_default`) and the plan usage (`name`, `max_accounts`, `used`, `left`). Call it first when the owner may have several accounts. - `get_setup_status`: start here. Account connected? Webhook subscribed? Token valid and days left? Rules active? Next steps. - `get_account`: one connected Instagram account (username, id, webhook status, token expiry, `is_default`). - `list_posts`: recent posts/reels with `media_id`, caption, permalink, thumbnail, and the rules watching each (`limit` 1–50). - `list_rules`: all rules with keywords, post, follow mode, link and on/off state. - `get_rule`: one rule with every field (`id`). - `create_rule`: create a rule. Required: `name`, `media_id` (or null = every post), `keywords`, `link_url`; texts default to friendly English. Created INACTIVE unless `active: true`. - `update_rule`: change only the fields passed (`id` + fields). - `set_rule_active`: turn a rule on or off (`id`, `active`). - `delete_rule`: delete a rule permanently. Ask the owner first. - `preview_rule`: dry run. The exact messages a saved rule (`rule_id`) or an unsaved draft (`rule`) would send. Nothing is saved or sent. - `test_comment`: dry run. Given `media_id` + comment `text`, which active rule would fire and what it would send. - `list_events`: the conversation log, newest first (filter `rule_id`, `kind`, `limit` ≤ 200). - `get_stats`: funnel for the last `days` (default 30), overall and per rule: comments, DMs, taps, asked to follow, links, errors. - `list_handoffs`: people who asked for a human; automation is paused for them. - `resume_conversation`: give a paused person (`igsid`) back to the automation. Workflow: `list_accounts` (ask which account if there are several) → `get_setup_status` → `list_posts` → draft the copy in the owner's language → `preview_rule` → `create_rule` → `test_comment` (one matching and one non-matching comment) → `set_rule_active` after the owner approves → `get_stats` / `list_events` / `list_handoffs`. Pass the same `account` to every call of one task. ## Rule fields - `name` (≤ 80), `media_id` (from `list_posts`, or null for every post; a post-specific rule wins over an every-post rule). - `keywords`: 1–20, each ≤ 40 chars. Case, accents and punctuation are ignored; whole-word (or whole-phrase) match. - `public_replies`: 0–10, ≤ 300 chars each, one picked at random. Empty = no public reply. - `opening_text` (first DM, the private reply) + `opening_button` (≤ 20). - `require_follow`: `false` = **soft invite** (default, recommended): everyone gets the link, and non-followers also get `follow_text` as an invitation. `true` = **hard gate**: the link goes only to followers. Meta's spam Community Standards forbid follow-gating, so use it only if the owner explicitly asks, and warn them. - `follow_text` + `follow_button` (≤ 20): the invitation (soft) or the condition plus a re-check button (hard). - `link_text` (keep ≤ 640, it is sent with a button), `link_url`, `link_button` (≤ 20). - `disclose_automation` (default true): appends "automated message · reply HUMAN to talk to a person" to the first DM. - `active`. ## Behaviour and limits - Instagram allows one private reply per comment, within 7 days of the comment. That reply is the first DM, sent at most once per person per rule. - The person's tap (quick reply) or typed answer is consent and opens a 24-hour window for the rest of the conversation. - The follow check is only possible after the person replies or taps a quick reply; a comment alone isn't enough. If consent is missing, the soft invite still sends the link and the hard gate asks the person to reply first. - Buttons may be refused (e.g. non-followers in the Requests folder). SayWink then falls back to plain text asking them to reply. - Human handoff: a DM containing words like human/humano/person/pessoa/agent/atendente/suporte/support pauses the automation for that person (`human_requested` event). See `list_handoffs` / `resume_conversation`. - Event kinds: comment_matched, comment_ignored, public_reply_sent, opening_sent, button_tapped, follow_missing, link_sent, human_requested, error. - The account must be a public Instagram professional account with "Allow access to messages" turned on (Settings → Messages and story replies → Message controls → Connected tools). - While the Meta app is in development mode, only app testers get DMs. Production needs App Review and Business Verification (Advanced Access). ## Optional - [Dashboard](/): connect Instagram, create or revoke API keys, see rules, events and handoffs.