AgentChat docs
AgentChat turns comments under your Instagram reels into DMs, followers and leads. You talk to it through your AI assistant (Claude, ChatGPT, Codex), through the REST API or in the dashboard. It only uses the official Instagram API.
Connect
There are two ways in. Both only see the data of your own Instagram account.
Way 1: connector with login (recommended)
Add this URL once as a connector. Your assistant opens a login page, you log in with Instagram and allow access. There is no key to copy.
https://agentchat.georgkinzel.de/mcp
- Claude.ai and the Claude apps: Settings, Connectors, Add custom connector. Name
AgentChat, URL as above. - Claude Code:
claude mcp add --transport http agentchat https://agentchat.georgkinzel.de/mcp, then run/mcpand choose AgentChat to log in. - ChatGPT: custom connectors need developer mode (Settings, Connectors). Add a connector with the URL above and authentication OAuth.
- Codex:
codex mcp add agentchat --url https://agentchat.georgkinzel.de/mcp, thencodex mcp login agentchat.
Then ask: “Check the status of AgentChat.” Connected apps are listed in your dashboard under Settings, Assistant, where you can revoke each one.
Way 2: API key
For everything without OAuth: n8n, Make, scripts, the REST API and MCP clients that can send a header. Create the key in your dashboard under Settings, Assistant, API key. It is shown once, right after it is created, and only stored as a hash. Lost it? Generate a new one, the old one stops working at once.
Always send it as a header, never in a URL:
Authorization: Bearer <your API key>
- REST:
curl -H "Authorization: Bearer $KEY" https://agentchat.georgkinzel.de/api/v1/status - MCP with a header: URL
https://agentchat.georgkinzel.de/mcpplus the header above. In Claude Code:claude mcp add --transport http agentchat https://agentchat.georgkinzel.de/mcp --header "Authorization: Bearer $KEY"
Quick start
One sentence to your assistant is enough:
Set up the keyword GUIDE for my latest reel. Reply under the comment with three variants, send the link only to followers, the link is https://example.com/guide.
The assistant finds the reel with list_posts, creates the automation with create_automation and shows you a preview of every message. Ask for preview_automation to see the link check as well. If comments are already there, it can answer them with run_automation_on_existing_comments (a dry run comes first).
Automations
Triggers
comment: a comment under a post or reel. Limit it to posts withmedia_ids, or leave it empty for all posts.dm: a direct message.story_reply: a reply to one of your stories.
Keywords are case insensitive. match_mode decides how they match: word (default), contains, exact or any (every text).
What a follower gets
- A public reply under the comment, picked at random from
public_replies. - A DM. Without follower check and without
opening_buttonit already holds the link. - With follower check: the DM has a button. Instagram only allows the follower check after the person wrote or tapped a button, so the tap comes first.
- Not following yet:
gate_textwith a button to check again. After 3 checks the link goes out anyway, because Instagram sometimes reports fresh follows late. - The link DM with up to two more link buttons (
extra_links). Clicks are counted through a redirect unlesstrack_clicksis off.
With email_gate the automation asks for the email before the link. An email in the reply is stored on the contact. A reply without an email gets email_retry_text once; after the second miss the link goes out anyway. A run waits 72 hours for the answer. Contacts with a stored email are not asked again (email_skip_if_known). For comments the email question is the one private reply and replaces the button DM. Optional webhook_url gets a POST on email_captured and link_sent, signed with webhook_secret if set.
Reminder
follow_up_text plus follow_up_minutes sends one reminder with the link to people who did not click. It only works inside the 24 hour window, so the maximum is 1380 minutes.
Next post
Reel not online yet? Use next_post: true. The automation waits and attaches itself to your next post, at most 2 minutes after you publish it.
Automation fields
| Parameter | Type | Meaning |
|---|---|---|
name | string | Internal name, e.g. 'Reel 16.10. VAULT' |
active | boolean | Active (default true) |
trigger | string: comment, dm, story_reply | comment = comment under a post/reel, dm = direct message, story_reply = reply to a story |
media_ids | array or null | comment only: IDs of the posts/reels (from list_posts). Empty/null = all posts |
next_post | boolean | comment only: wait for the next new post/reel and attach to it automatically (at most 2 minutes after posting). Ideal when the reel is not online yet |
keywords | array of string | Trigger words, case-insensitive |
match_mode | string: word, contains, exact, any | word (default): word appears in the text. contains: substring anywhere. exact: whole text = word. any: every text |
exclude_keywords | array of string | Do not trigger if one of these words appears |
public_replies | array of string | comment only: replies under the comment, one is picked at random. E.g. ['Sent you the link {username} 📩']. Empty = no public reply |
opening_text | string | First DM with button (default: "Hey {username}! Tap the button and I'll send you the link.") |
opening_button | string | Button of the first DM (default with follower check: "Send link"). Without follower check and without opening_button the link goes out in the first DM |
follow_gate | boolean | Link only for followers. Non-followers get gate_text with a button to check again |
gate_text | string | Text for non-followers (default: "Almost there! Follow me real quick, then tap the button again and the link comes right away.") |
gate_button | string | Button to check again (default: "I follow you now") |
link_url | string | Target link (https://...) |
link_text | string | Text of the DM with the link (default: "Here's your link 👇") |
link_button | string | Title of the link button (default: "Open") |
extra_links | array of object | Up to 2 more link buttons in the link DM |
follow_up_text | string | Reminder for people who did not click the link, e.g. 'Did you check it out yet? 👀'. Sent once, with the link button, only inside the 24h window |
follow_up_minutes | integer | Minutes without a click before the reminder (e.g. 120). 0 = off, max 1380 |
email_gate | boolean | Ask for the email before sending the link (default false). See the server instructions for the order with comments and follow_gate |
email_text | string | Email question (default: "Quick one: which email should I send it to? 📩") |
email_retry_text | string | Sent once if the reply contains no email; after the second miss the link goes out anyway (default: "Hm, that didn't look like an email. Just type it in here 🙂") |
email_skip_if_known | boolean | Skip the email question for contacts with a stored email (default true) |
webhook_url | string or null | Optional https URL that gets a POST on email_captured and link_sent. No private or local addresses. null = off |
webhook_secret | string or null | Optional secret; the body is signed as header X-AgentChat-Signature: sha256=<HMAC-SHA256 hex>. Never shown again in responses |
track_clicks | boolean | Count clicks through our own redirect (default true) |
tags | array of string | Tags the contact gets |
once_per_user | boolean | Each user gets this automation only once (default true) |
priority | integer | Higher number wins when several match (default 0) |
notes | string | Note |
skip_if_answered | boolean | comment only: skip the comment if your account already replied to it without AgentChat, e.g. ManyChat (default true). The run gets state skipped_other_tool |
Placeholders in texts: {username} and {name}. Button titles up to 20 characters, DM texts up to 640.
Preview and go live
preview_automation shows how an automation looks for a follower: the public reply, every DM with its buttons and the link. It also checks the link live (HEAD request, GET if the server refuses HEAD, 5 seconds; private addresses are not fetched) and flags broken links.
Imported automations start as drafts. Drafts answer nothing. Check the preview, then switch them on with go_live (single ids, one import batch or all drafts). The dashboard shows the same preview as a chat for every draft.
Keyword links
Save the link for a comment keyword once with set_keyword_link (list_keyword_links shows all). suggest_automations_from_posts then fills in the link when it finds the keyword in a caption.
Switch from ManyChat
The goal: no reel goes quiet during the switch and nobody gets the same DM twice. Fastest way in Claude Code: install the plugin and type /agentchat:manychat. Claude tells you first what it needs (Claude in Chrome on, logged in to ManyChat) and then walks you through. The full guide is on Switch from ManyChat.
- Connect AgentChat. Keep ManyChat running.
- Export from ManyChat, read only: a browser agent reads your automations (MCP prompt
manychat_migration_promptor the script in the skill) and your contacts (CSV, see below). Or paste screenshots or a list, or letsuggest_automations_from_postsread your captions. import_automationswithdry_run: trueshows the post it found for each entry, warnings and errors. Withdry_run: falseevery valid entry is created as a draft.- Check
preview_automationfor every draft and import the contacts. go_live. While ManyChat is still connected, AgentChat skips comments ManyChat already answered.- Remove ManyChat in the Instagram app: Settings, App and website permissions, Apps and websites, ManyChat, Remove. That stops all ManyChat automations at once. You can connect it again in ManyChat any time.
finish_migrationwithconfirm_manychat_disconnected: trueswitches on follower check and buttons. Then thegap_fillcalls (run_automation_on_existing_commentswithsince_minutes: 30) answer comments from the switch that nobody answered.
Contacts and DM history
Your contacts move with you, including where they came from. The DMs themselves live at Instagram, so AgentChat loads them from there.
- ManyChat has no CSV export for contacts. A browser agent (Claude in Chrome, Codex) reads them from the ManyChat web app, read only, and saves a CSV after your OK. The script is in the AgentChat skill. It changes nothing in ManyChat.
import_contactswith the CSV text (or a JSON list). The dry run comes first and counts new, updated, skipped and errors, with examples.- Column names are matched loosely: Instagram Username, ig_username or username; Instagram ID, ig_id or user_id; First Name, Last Name, Full Name, Email, Phone, Tags, Subscribed or Opt-in date, Last Interaction, Status. Other columns become
custom_fields. Invalid emails are skipped and listed. - Origin: a tag like
link_clicked (<date>)or an automation or widget column becomes the contact'ssourceand marks the contact as clicked. If an AgentChat automation has the same name or keyword, the contact is linked to it; otherwise passsource_map. - Existing contacts are matched by Instagram ID, else by username (case does not matter). The Instagram ID from ManyChat is the same one AgentChat sees, so new contacts are linked right away. AgentChat only fills empty fields and adds tags, it never overwrites. Run it with
dry_run: falsewhen the numbers look right. backfill_conversationsthen reads your Instagram conversations (read only) and saves the messages on the contacts, skipping messages it already has. It runs in the background in small steps;statusshows the progress underbackfill. Every contact shows the conversation in the dashboard.
Limits from Meta: Instagram returns details only for the 20 most recent messages of each conversation, and conversations in the Requests folder that were inactive for 30 days are not returned (Conversations API, checked on 18 October 2026). Imported contacts without an Instagram ID that AgentChat has seen get linked as soon as they comment or write, or when the backfill finds their conversation: ManyChat's Instagram ID is the same one the Instagram API gives AgentChat (checked on 12 shared contacts), so contacts with an ID are linked right away; contacts without one are linked by username.
Transition mode
While ManyChat is connected it owns your conversations, and AgentChat may only send the one private reply to a comment. Imported automations therefore start in transition mode: the link goes out directly in that reply. Follower check, button, email question and reminder are saved as target settings. DM and story automations start paused. finish_migration switches everything to the target settings. Instagram has no API that tells whether ManyChat still owns your conversations, so without the confirmation it only shows what would change.
Protection against double DMs
Instagram allows exactly one private reply per comment. Before AgentChat answers a comment it reads the replies under it. If your account already replied and that reply did not come from AgentChat (for example from ManyChat), AgentChat sends neither the public reply nor the DM and marks the run as skipped_other_tool. If Meta rejects the private reply because the comment was already answered, that also counts as skipped. If the reply list cannot be loaded, the automation runs as usual. This is skip_if_answered, on by default. stats counts skipped_other_tool separately.
Old ManyChat buttons
People keep tapping buttons from old ManyChat messages after the switch. AgentChat matches such a tap (or a reply that is exactly an old button text such as “Link schicken” or “ich folge jetzt”) to the comment automation of the person's last comment within 7 days, remembers the button for the next person if that person commented on only one post and continues with follower check and link. You see legacy_tap_resolved in the activity. If nothing matches, the activity shows unhandled_button or unhandled_dm and the operator is notified. The same tap arriving twice (webhook and polling) sends only one message.
Thread owner and follower check
A follow up message that fails with “not the thread owner” means another app (often ManyChat, sometimes an older Meta app) owns the conversation. You see thread_owner_blocked in the activity and a warning in status and dashboard until finish_migration ran. That is why follower check and email only switch on after the migration is finished.
On “not the thread owner” AgentChat tries once to take over the conversation and then sends the message again once. Meta documents the takeover only for Facebook Page logins, so on accounts where Instagram rejects it, AgentChat remembers that and does not try again. Then the operator gets the contact and the link to send by hand.
Reel scheduling
Your assistant can publish a reel now or at a set time and attach a comment automation to exactly that reel. The server operator has to switch publishing on; status shows it under publishing.
upload_videoreturns a one time upload URL (1 hour, MP4 or MOV). Upload withcurl -T reel.mp4 -H "Content-Type: video/mp4" <upload_url>. Or skip this and pass a publicvideo_url.schedule_reelwithvideo_idorvideo_url,caption,publish_at(nowor ISO time with time zone) and optionalautomation.- The server checks Instagram's daily publishing limit first (
get_publishing_limit) and publishes at most 2 minutes after the set time. Uploaded files are deleted right after publishing, cancelling or failing. list_scheduledandcancel_scheduledshow and cancel.
If status shows publishing.permission as missing or unknown, log in with Instagram once more on /start and allow publishing.
REST API
The MCP tools as REST endpoints (all except check_follower, subscribe_webhooks, refresh_token and billing_status, which are MCP only) under https://agentchat.georgkinzel.de/api/v1, with your API key as Bearer header. The full description is openapi.json (OpenAPI 3.1, no key needed).
curl -H "Authorization: Bearer $KEY" https://agentchat.georgkinzel.de/api/v1/automations
curl -X PATCH -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"active":false}' https://agentchat.georgkinzel.de/api/v1/automations/3
curl -H "Authorization: Bearer $KEY" "https://agentchat.georgkinzel.de/api/v1/export/contacts?format=csv"
Errors always come as {"error": "..."}: 400 validation, 401 missing or wrong key, 402 plan needed, 404 not found, 429 rate limit, 502 Instagram error.
MCP tools reference
Generated from the tool definitions of this server. Your assistant sees the same list.
status
Check the connection: Instagram account, token expiry, webhook subscription, counts, webhook URL, migration and publishing state; for the operator also health (degraded plus problems, as /health).
No parameters.
list_posts
Latest posts and reels with ID, caption, link, comment count and the automations attached to them.
| Parameter | Type | Meaning |
|---|---|---|
limit | integer | Default 12, max 50 |
list_automations
All automations with short stats.
No parameters.
get_automation
One automation in full, including funnel numbers.
| Parameter | Type | Meaning |
|---|---|---|
id (required) | integer |
create_automation
Create a new automation. Returns it plus a preview of the messages.
Plus every field from Automation fields.
update_automation
Change fields of an automation (only the given ones). Pause with active=false.
| Parameter | Type | Meaning |
|---|---|---|
id (required) | integer |
Plus every field from Automation fields.
delete_automation
Delete an automation (history stays in the export).
| Parameter | Type | Meaning |
|---|---|---|
id (required) | integer |
test_automation
Dry run: which automation would react to this text and which messages would go out? Sends nothing.
| Parameter | Type | Meaning |
|---|---|---|
text (required) | string | |
trigger (required) | string: comment, dm, story_reply | |
media_id | string | |
follows | boolean | Assumption for the follower check (default true) |
run_automation_on_existing_comments
Apply an automation to comments that already exist on a post (only comments younger than 7 days, each comment only once). Default is dry_run=true: only shows who would get something.
| Parameter | Type | Meaning |
|---|---|---|
automation_id (required) | integer | |
media_id (required) | string | |
dry_run | boolean | |
limit | integer | max comments, default 100 |
since_minutes | integer | Only comments from the last N minutes, e.g. 30 for the switch from ManyChat. Default: all younger than 7 days |
list_comments
Comments under a post/reel. answered is true if your account replied under the comment or AgentChat sent something for it (reply or DM); answered_by says who: agentchat, other (for example ManyChat) or null.
| Parameter | Type | Meaning |
|---|---|---|
media_id (required) | string | |
limit | integer | |
only_unanswered | boolean |
reply_to_comment
Reply publicly to a comment.
| Parameter | Type | Meaning |
|---|---|---|
comment_id (required) | string | |
text (required) | string |
send_dm
Send a DM to a contact. Only works within 24 hours after their last message or button tap.
| Parameter | Type | Meaning |
|---|---|---|
contact (required) | string | Instagram ID or @username of the contact |
text (required) | string | |
link_url | string | |
button_title | string |
check_follower
Checks live whether a contact follows the connected account (only works if the contact has written or tapped a button before).
| Parameter | Type | Meaning |
|---|---|---|
contact (required) | string | Instagram ID or @username of the contact |
list_contacts
Filter and list contacts.
| Parameter | Type | Meaning |
|---|---|---|
search | string | Part of the username |
tag | string | |
follows | boolean | |
has_email | boolean | true = only contacts with an email, false = only without |
clicked | boolean | true = only contacts that clicked a link, false = only those that did not |
automation_id | integer | Only contacts that triggered this automation |
since | string | Last active since (YYYY-MM-DD) |
limit | integer | Default 50, max 500 |
offset | integer |
get_contact
One contact with all runs and the history.
| Parameter | Type | Meaning |
|---|---|---|
contact (required) | string | Instagram ID or @username of the contact |
update_contact
Set tags, email or note of a contact.
| Parameter | Type | Meaning |
|---|---|---|
contact (required) | string | Instagram ID or @username of the contact |
add_tags | array of string | |
remove_tags | array of string | |
email | string | |
notes | string |
activity
Latest events (incoming comments/DMs, sent messages, errors).
| Parameter | Type | Meaning |
|---|---|---|
limit | integer | Default 50 |
kind | string | e.g. comment_in, dm_in, button_in, dm_out, comment_reply_out, follow_check, email_captured, email_given_up, email_expired, webhook_out, webhook_error, error |
automation_id | integer | |
contact | string | Instagram ID or @username of the contact |
stats
Funnel per automation: triggered, DM out, button tapped, at follower gate, asked for email, email captured, link out, clicked, errors.
| Parameter | Type | Meaning |
|---|---|---|
days | integer | Period, default 30 |
export_data
Data export. With table the rows come back directly as CSV (up to 2000 rows). Without table it lists the tables and the REST download URLs (they need the API key as Bearer header).
| Parameter | Type | Meaning |
|---|---|---|
table | string: contacts, automations, runs, events, clicks, scheduled_posts, videos, messages | |
since | string | YYYY-MM-DD |
inline | boolean | Kept for compatibility: the rows of a table always come back inline |
subscribe_webhooks
Subscribe the Instagram account to webhooks (comments, messages, messaging_postbacks). Call once after setup.
No parameters.
refresh_token
Extend the Instagram token by 60 days right now (otherwise runs daily automatically).
No parameters.
billing_status
Subscription of this account: plan, status, trial end, whether automations may send, and the upgrade link (subscribe or manage the subscription).
No parameters.
upload_video
Get a one-time upload URL for a reel video (MP4 or MOV). Upload the file with HTTP PUT within 1 hour, e.g. curl -T reel.mp4 -H "Content-Type: video/mp4" <upload_url>. Returns video_id for schedule_reel. The file is stored on the server only until the reel is published, cancelled or failed, at most 7 days. Instagram accepts reels with 3 s to 15 min and up to 300 MB. Needs the Node server; on Cloudflare pass video_url to schedule_reel instead.
| Parameter | Type | Meaning |
|---|---|---|
filename | string | Optional original file name, only for your overview |
content_type | string: video/mp4, video/quicktime | Default video/mp4 |
schedule_reel
Publish a reel now or at a set time. Source: video_id (from upload_video) or video_url (public URL Instagram downloads itself). Checks the daily publishing limit first. Optional automation: same fields as create_automation (trigger is always comment); it waits like next_post and attaches to exactly this reel once it is published. Publishing happens at most 2 minutes after publish_at.
| Parameter | Type | Meaning |
|---|---|---|
video_id | integer | ID from upload_video |
video_url | string | Public https URL of an MP4/MOV, instead of video_id. Must still work at publish time |
caption | string | Caption, max 2200 characters, 30 hashtags, 20 @mentions |
publish_at (required) | string | 'now' or ISO 8601 with time zone, e.g. 2026-10-20T18:00:00+02:00. Uploaded files: at most 7 days after the upload |
cover_url | string | Optional public JPEG for the cover (wins over thumb_offset) |
thumb_offset | integer | Optional cover frame in milliseconds from the start |
share_to_feed | boolean | true = reel may also appear in the feed, false = Reels tab only. Default: Instagram's default |
trial | boolean | Trial reel: shown only to non-followers first; graduate it manually in the Instagram app |
automation | object | Optional comment automation for this reel (same fields as create_automation) |
list_scheduled
Scheduled, published, failed and cancelled reels of this account, newest first.
| Parameter | Type | Meaning |
|---|---|---|
status | string: open, published, failed, cancelled, all | Default open |
limit | integer | Default 20, max 100 |
cancel_scheduled
Cancel a scheduled reel that is not published yet. The uploaded file is deleted right away. An attached automation stays paused (delete it with delete_automation if not needed).
| Parameter | Type | Meaning |
|---|---|---|
id (required) | integer |
get_publishing_limit
Instagram's publishing limit for this account: posts published via the API in the last 24 hours, the maximum, and reels already scheduled for the next 24 hours.
No parameters.
import_automations
Bulk import for switching from ManyChat: all automations in one call. dry_run=true (default) only resolves the posts (permalink, caption part, media_id or next_post), validates and shows per entry what would be created plus warnings (post not found, keyword conflict, follower check and email need thread ownership). dry_run=false creates every valid entry (each on its own, invalid ones are skipped), by default as drafts with an import_batch: check preview_automation, then go_live. go_live returns the order to follow without a gap: the AgentChat automation is live, then pause it in ManyChat (checklist), then gap-fill the last 30 minutes with run_automation_on_existing_comments. transition_mode (default true while ManyChat is still connected): follower check, button, email and reminder are stored as target settings and switched on later by finish_migration; until then the link goes out directly in the one private reply.
| Parameter | Type | Meaning |
|---|---|---|
automations (required) | array of object | The automations to import, e.g. read from ManyChat screenshots or from suggest_automations_from_posts |
dry_run | boolean | Default true: only check and show, create nothing |
start_paused | boolean | Create them paused (default false). Then turn each one on with update_automation active=true |
transition_mode | boolean | Default true until finish_migration ran: run without thread-ownership features until ManyChat is disconnected |
draft | boolean | Default true: create as drafts that answer nothing until go_live (check preview_automation first). false = live right away |
suggest_automations_from_posts
Scans the captions of the latest posts for comment-keyword calls like 'Comment GUIDE', 'Kommentier KI', 'Kommentiere „VAULT“', 'type AI' or 'DM me AUDIT' and suggests one automation per post. Posts that already have an AgentChat automation are flagged. import_input can be passed straight to import_automations; link_url is taken from the keyword link library or a URL in the caption, otherwise null (add the link first).
| Parameter | Type | Meaning |
|---|---|---|
limit | integer | Number of latest posts to scan, default 12, max 50 |
finish_migration
Ends the transition mode after ManyChat is disconnected in Instagram (Settings → App and website permissions → Apps and websites): switches every automation in transition mode to its target settings (follower check, button, email, reminder, DM automations on). Instagram has no API that tells whether ManyChat still owns your conversations, so without confirm_manychat_disconnected=true this only shows what would change.
| Parameter | Type | Meaning |
|---|---|---|
confirm_manychat_disconnected | boolean | true = ManyChat is disconnected in Instagram, switch now |
automation_ids | array of integer | Optional: only these automations |
set_keyword_link
Keyword link library for caption suggestions: keyword → link. url null removes the keyword.
| Parameter | Type | Meaning |
|---|---|---|
keyword (required) | string | |
url | string or null | https://... or null to remove |
list_keyword_links
All entries of the keyword link library.
No parameters.
preview_automation
Shows how an automation looks for the follower: public reply under the comment, every DM with its buttons and the link, plus a live link check (HTTP status, broken links are flagged). Works for drafts. In transition mode it also shows what changes after finish_migration.
| Parameter | Type | Meaning |
|---|---|---|
id (required) | integer |
go_live
Switch drafts live: one or more automation_ids, every draft of one import (import_batch) or all drafts (all_drafts=true). Returns link checks and the order without a gap: live now, then pause in ManyChat (manychat_pause_checklist), then the gap_fill calls.
| Parameter | Type | Meaning |
|---|---|---|
automation_ids | array of integer | |
import_batch | string | From the import_automations result |
all_drafts | boolean |
import_contacts
Import contacts from ManyChat as CSV (ManyChat has no export: a browser agent reads them with the AgentChat skill script) or from a JSON list. Column names are matched loosely (Instagram Username / ig_username / username, Instagram ID / ig_id / user_id, First Name, Last Name, Full Name, Email, Phone, Tags, Subscribed / Opt-in date, Last Interaction, Status, custom fields). Tags like 'link_clicked (<date>)' and automation or widget names become the contact's source and mark it as clicked; a source is linked to an AgentChat automation with the same name or keyword (or via source_map). Matches existing contacts by Instagram ID, else by username (case-insensitive) and only fills empty fields and adds tags, never overwrites. dry_run (default true) shows counts new / updated / skipped / errors with examples. Emails are validated.
| Parameter | Type | Meaning |
|---|---|---|
csv | string | Text of the CSV export (first row = column names) |
contacts | array of object | Instead of csv: list of contact objects with the same field names |
dry_run | boolean | Default true: only count and show examples, change nothing |
source_map | object | Optional: ManyChat automation name or tag → AgentChat automation id, e.g. {"Agent vault copy 4": 12} |
backfill_conversations
Load the DM history from Instagram (read only, sends nothing): reads your conversations page by page with the 20 most recent messages each, saves them on the contacts (creates missing contacts with their username) and skips messages it already has (message ID). Runs in steps in the background every 2 minutes; progress is in status.backfill. Instagram only gives the 20 most recent messages per conversation.
| Parameter | Type | Meaning |
|---|---|---|
max_conversations | integer | Stop after this many conversations (default 1000, max 10000) |
restart | boolean | Start again from the newest conversation even if a backfill is running |
cancel | boolean | Stop a running backfill. Loaded messages stay |
Prompts
manychat_migration_prompt: Prompt for a browser agent that reads ManyChat without changing anything and imports into AgentChat as drafts.migrate_from_manychat: Guided move from ManyChat: say what is needed, export automations and contacts, drafts with preview, go live, remove ManyChat in Instagram, finish_migration.new_reel_automation: Create a comment keyword automation for one reel (posted or next), with preview and link check before it goes live.
Limits
- One private reply per comment, only up to 7 days after the comment.
- More DMs only within 24 hours after the person's last message or button tap.
- The follower check only works after the person wrote or tapped a button.
- Button titles up to 20 characters, DM texts up to 640 characters.
Sending limits per account
To protect all accounts from being flagged as spam, each account sends at most 300 messages (DMs plus comment replies) per hour and 3000 per day, during the free trial 60 per hour and 300 per day. Private replies to comments over the limit, or blocked by an Instagram rate limit, are not lost: they wait and go out automatically within the 7 days Instagram allows.
Rate limits of this server
| Area | Requests | Window |
|---|---|---|
| Login pages (/start, /connect, /auth/callback, /oauth/authorize) per IP | 10 | per minute |
| REST API per account | 120 | per minute |
| REST API per IP | 300 | per minute |
| REST API writes (POST, PATCH, PUT, DELETE) per account | 30 | per minute |
| MCP per account | 120 | per minute |
| MCP per IP | 300 | per minute |
| Wrong keys per IP (then the IP is locked for a while) | 20 | per minute |
| Dashboard forms per account | 60 | per minute |
| Reel uploads per account | 10 | per hour |
| OAuth client registration per IP | 30 | per minute |
| OAuth token requests per IP | 300 | per minute |
Over the limit you get 429 with Retry-After in seconds.
Troubleshooting
- Nothing happens on a comment: ask for
status. Check that webhooks are subscribed (otherwisesubscribe_webhooks), that the automation is active and not a draft, and usetest_automationwith the comment text. - The DM with the link never arrived: look at
activity. Instagram rejects DMs outside the 24 hour window; the person has to write or tap a button first. - “not the thread owner” or
thread_owner_blocked: Another app (often ManyChat, sometimes an older Meta app) owns the conversation. Remove it in Instagram (Settings, App and website permissions, Apps and websites) or in Meta Business Suite under conversation routing, then runfinish_migration. If only single threads are blocked while others go through, it does not have to be ManyChat: look for an older Meta app. - Runs show
skipped_other_tool: your account had already answered that comment without AgentChat. This is the double DM protection working. - Connection shows
token_invalid: log in with Instagram again on /start. After the login AgentChat catches up on its own: comments from the outage (Instagram allows a private reply up to 7 days), runs that stopped and DMs from the last 23 hours. The activity showsrecovery_donewith the numbers,recovery_not_possiblefor what was too old. list_commentsshowsanswered_by:agentchatmeans AgentChat replied or sent the DM,othermeans your account replied without AgentChat (for example ManyChat).- Your assistant says the token is invalid or expired: reconnect the connector. A wrong API key gives 401; too many wrong keys lock the IP for a while.
- A tool answers that AgentChat is paused: the free trial ended or the payment failed. Choose a plan on your plan page. Reading and exporting keep working.
Skills for Claude and Codex
Ready-made workflows for your assistant: connect, switch from ManyChat, a new reel, stats, scheduling and troubleshooting. They ask before anything goes live or reaches real people. Source: https://github.com/epictaste/agentchat-skills
- Claude Code:
/plugin marketplace add epictaste/agentchat-skills, then/plugin install agentchat@agentchat. This also adds the AgentChat connector. Or paste the prompt from the home page and Claude installs it. Short commands:/agentchat:manychatand/agentchat:reel. - Any agent with Agent Skills, including Codex:
npx skills add epictaste/agentchat-skills - Claude.ai: download the folder
plugins/agentchat/skills/agentchatfrom the repository as a ZIP and upload it under Settings, Capabilities, Skills.