Developers
DMpop API
Create comment-to-DM campaigns from your own tools. A content pipeline can publish a reel and switch on its DM automation in the same step.
Authentication
Create a key in Settings → API keys. It is shown once, so store it somewhere safe. Send it with every request:
Authorization: Bearer dmp_your_key_here
Base URL: https://app.dmpop.com/api/v1. Requests and responses are JSON. Each key can make 60 requests a minute. A key acts for its whole workspace, so treat it like a password.
Typical pipeline
Either create the campaign before you post, and DMpop attaches it to the next reel within about five minutes of it going live:
curl -X POST https://app.dmpop.com/api/v1/campaigns \
-H "Authorization: Bearer $DMPOP_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Hooks guide reel",
"nextReel": true,
"keywords": ["GUIDE"],
"message": "Hey {username}, here is the guide you asked for.",
"link": "https://example.com/guide",
"buttonLabel": "Get the guide",
"publicReplies": ["Sent you a DM!"]
}'Or, if your pipeline publishes first and knows the post ID, attach it directly with "postId": "1789..." instead of nextReel.
Use with Claude, Codex or Cursor (MCP)
DMpop is also an MCP server, so an AI assistant can list your posts and create, pause or delete campaigns when you ask it to. Use the same API key.
Claude Code
claude mcp add --transport http dmpop https://app.dmpop.com/mcp \ --header "Authorization: Bearer dmp_your_key_here"
Codex (~/.codex/config.toml)
[mcp_servers.dmpop] url = "https://app.dmpop.com/mcp" bearer_token_env_var = "DMPOP_API_KEY"
Cursor and other clients (mcp.json)
{
"mcpServers": {
"dmpop": {
"url": "https://app.dmpop.com/mcp",
"headers": { "Authorization": "Bearer dmp_your_key_here" }
}
}
}Tools: list_instagram_accounts, list_recent_posts, list_campaigns, get_campaign, create_campaign, update_campaign and delete_campaign. Then just ask, for example: “Set up a DMpop campaign on my next reel: when people comment GUIDE, DM them https://example.com/guide.”
Endpoints
GET /accounts: connected Instagram accounts.GET /posts?accountId=&limit=12: recent posts and reels with their IDs (up to 25).GET /campaigns: all campaigns with their numbers.POST /campaigns: create a campaign.GET /campaigns/{id}: one campaign with sends, skips, failures, clicks and click rate.PATCH /campaigns/{id}: change any field. Only the fields you send change. Send{"active": false}to pause.DELETE /campaigns/{id}: delete a campaign.
Campaign fields
| Field | Type | What it does |
|---|---|---|
| name | string, required | A label for the campaign. |
| message | string, required | The DM text. Use {username} for the person's handle and {link} to place the tracked link in the text. |
| nextReel | boolean | Attach to the next reel you publish. Use this when the campaign is created before posting. |
| postId | string | Attach to an existing post or reel. Get IDs from GET /posts. |
| anyPost | boolean | Run on every post. Exactly one of nextReel, postId or anyPost is needed. |
| keywords | string[] | Up to 10 trigger words, e.g. ["GUIDE"]. Needed unless anyWord is true. |
| anyWord | boolean | Reply to every comment, whatever it says. |
| wholeWord | boolean | Match whole words only. Default true. |
| link | URL | The link to send. It becomes a tracked link so clicks are counted. |
| buttonLabel | string, max 20 | Text on the link button, e.g. "Get the guide". |
| secondLink, secondButtonLabel | URL, string | An optional second link button. |
| publicReplies | string[] | Public replies posted under the comment. One is picked at random each time. |
| openingMessage, openingButtonLabel | string, string | Send a short opener with a button first; the link follows when it is tapped. |
| requireFollow, followPrompt, followButtonLabel | boolean, string, string | Only send the link to people who follow you. |
| followUpMessage, followUpDelayMinutes | string, 0 to 1440 | An optional later message. |
| alsoOnDms | boolean | Also reply when someone sends the keyword in a DM or Story reply. |
| accountId | string | Which connected account to use. Defaults to the most recently connected one. |
| active | boolean | Default true. Set false to create the campaign paused. |
Responses and errors
Successful calls return { "data": ... }. A campaign looks like this:
{
"data": {
"id": "cmv...",
"name": "Hooks guide reel",
"active": true,
"trigger": "next_reel",
"postId": null,
"keywords": ["GUIDE"],
"links": [{ "url": "https://example.com/guide", "label": null, "trackedUrl": "https://app.dmpop.com/r/..." }],
"stats": { "sent": 0, "skipped": 0, "failed": 0, "clicks": 0, "ctr": 0 }
}
}Errors return { "error": { "message": "...", "details": ... } } with a status code: 400 for an invalid request, 401 for a missing or revoked key, 404 for something that doesn't exist, 429 when the rate limit is hit. Unknown fields are rejected, so typos don't pass silently.
Questions: hello@dmpop.com. Campaigns made through the API follow the same rules as the dashboard, including Instagram's limits and our Terms.