# Choose your interface Source: https://docs.reply.io/agents/choose-your-interface MCP vs Skills vs CLI vs API — how the four Reply.io access layers differ and which to pick. MCP, Skills, CLI, and API are not separate products — they are four ways to access the same Reply.io platform. Same account, same [API key](/api-reference/authentication), same object model, same [rate limits](/api-reference/rate-limits). ## Comparison | | **MCP** | **Skills** | **CLI** | **API** | | ------------------- | -------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------ | | **Best for** | Agents in MCP clients (Claude, Cursor) | Coding agents that need procedure, not just tools | Shell scripts, CI, coding agents | Production integrations, webhooks, bulk | | **Granularity** | 70 curated tools | 4 multi-step workflows (v1) | 4 command groups + `reply api` passthrough | Every endpoint | | **Install cost** | One client config entry | CLI + one `git clone` | One `npm install` | None (HTTP) | | **Safety built in** | `readOnlyHint`/`destructiveHint` annotations | Hard confirmation gates + previews | None — the caller gates | Scoped keys only | | **Coverage today** | Day-to-day operations + Jason AI SDR | Core outreach loop | Auth and identity, plus every endpoint via `reply api` | Full surface | | **Start** | [Connect](/mcp/connect) | [Install](/skills/overview#install) | [Install](/cli/overview#install) | [Get a key](/api-reference/authentication) | ## Decision rules * **Your agent runs in an MCP client** (Claude, Cursor, Make, n8n) → use **[MCP](/mcp/overview)**. Richest interactive surface, and the only one with per-tool safety annotations the client can gate on automatically. * **Your agent has a shell** (Claude Code, Codex, CI pipelines) → use the **[CLI](/cli/overview)**, and add the **[Skill](/skills/overview)** so it follows proven procedure — previews, verification steps, and confirmation gates included. * **You're building a production integration** — webhooks, bulk imports, background jobs, or anything not exposed as a tool/command → use the **[REST API](/api-reference/introduction)**. * **You want Jason (AI SDR) programmable** — approval queues, knowledge bases, offers, playbooks → **[MCP](/mcp/overview)** has the richest Jason toolset today; the REST API covers the knowledge/offer/playbook layer. ## They compose The layers are designed to be combined, not chosen once: * The **Skill drives the CLI** — the skill decides *what* to do; the CLI executes it. You can use the CLI without the skill; the skill requires the CLI. * An agent can follow the **skill's procedure using MCP tools** instead of CLI commands — the workflows describe platform operations, not surface-specific calls. * **MCP for the interactive path, REST for the exhaustive one** — drop to REST for bulk imports/updates, report exports, and webhook administration that aren't exposed as tools. * A **CLI cron job** can do the weekly hygiene sweep while an **MCP agent** handles the conversational work in the same workspace. ## Consistent everywhere Whatever surface you choose, these hold: * **One key, scoped** — `domain:verb` scopes (`contacts:read`, `sequences:operate`, …) behave identically on every surface. See [Authentication](/api-reference/authentication). * **One object model** — contacts, lists, sequences, threads, tasks, and Jason objects carry the same IDs and semantics everywhere. * **One rate-limit budget** — see [Rate limits](/api-reference/rate-limits). * **Same safety expectations** — see [Agent safety rules](/agents/safety). # Agentic capabilities Source: https://docs.reply.io/agents/overview The capability map for agents on the Reply.io platform — outcomes, access layers, and where the human boundary sits. Reply.io is a sales-engagement platform an AI agent can operate end to end: find and manage contacts, launch multichannel outreach, triage and answer replies, pull performance data, and program Jason — Reply's AI SDR — as a supervised autopilot. Everything runs behind one scoped [API key](/api-reference/authentication) across four access layers. ## What an agent can do today | Outcome | Status | Where to start | | ---------------------------------------------------------------- | -------------- | -------------------------------------------------------------------- | | Import and manage contacts, lists, accounts | ✅ Available | [Import and clean contacts](/guides/import-contacts) | | Launch multichannel sequences (email + LinkedIn) | ✅ Available | [Launch multichannel outreach](/guides/launch-outreach) | | Manage and optimize running sequences | ✅ Available | [Improve sequences every cycle](/guides/improve-sequences) | | Triage the inbox and send approved replies | ✅ Available | [Convert replies into meetings](/guides/convert-replies-to-meetings) | | Pull reports and per-sequence stats | ✅ Available | [Decide what to scale or fix](/guides/analyze-performance) | | Configure Jason AI SDR (knowledge, offers, playbooks, approvals) | ✅ Available | [Build a supervised AI SDR](/guides/build-an-ai-sdr) | | Event-driven automation via webhooks | ✅ Available | [Automate outbound end-to-end](/guides/automate-outbound) | | Validate emails, enforce blacklists, keep lists clean | ✅ Available | [Automate outbound end-to-end](/guides/automate-outbound) | | Search the 1B+ B2B database for new prospects | 🔜 Coming soon | [Find your ideal prospects](/guides/find-ideal-prospects) | | Waterfall-enrich contacts (emails, phones, firmographics) | 🔜 Coming soon | [Find your ideal prospects](/guides/find-ideal-prospects) | ## The four access layers All four surfaces operate the same platform — same key, same objects, same limits. They differ in how an agent consumes them: ``` ┌────────────────────────────┐ MCP client ──▶ │ MCP · 70 annotated tools │ ──┐ └────────────────────────────┘ │ ┌────────────────────────────┐ │ ┌───────────────┐ Coding agent ──▶ │ Skill · packaged workflows│ ──┤ ───▶ │ Reply.io v3 │ │ └─▶ CLI · `reply` command │ │ │ platform │ └────────────────────────────┘ │ └───────────────┘ ┌────────────────────────────┐ │ Any program ──▶ │ REST API · api.reply.io/v3│ ──┘ └────────────────────────────┘ ``` * **[MCP](/mcp/overview)** — direct tool access for AI agents in MCP clients. * **[Skills](/skills/overview)** — packaged workflows and guardrails; the skill decides *what* to do, the CLI does it. * **[CLI](/cli/overview)** — terminal and automation interface with JSON output and safety flags. * **[API](/api-reference/introduction)** — low-level programmable integration; the exhaustive surface. Not sure which fits? [Choose your interface](/agents/choose-your-interface). ## The human boundary today An agent can operate everything behind the API key. Three things still need a human: 1. **Account creation** — a human signs up (14-day free trial, no credit card required). 2. **API key issuance** — created in the Reply app under **Settings → API Keys** and handed to the agent. Keys support granular scopes — see [Authentication](/api-reference/authentication). 3. **Billing** — plan upgrades and credit purchases happen in the Reply app. ## Next steps MCP vs Skills vs CLI vs API — decision rules and a comparison table. High-stakes gating, scoped keys, and rate-limit etiquette across all surfaces. Ready-to-paste prompts for agents operating Reply. Task-based guides for every outcome in the table above. # Drop-in system prompts Source: https://docs.reply.io/agents/prompts Ready-to-paste system prompts for AI agents operating Reply.io — cross-surface, MCP, and CLI variants. Paste these into an agent's system prompt to encode the platform's object model, safety rules, and error handling. Pick the variant matching your agent's surface. ## Cross-surface platform prompt Works for any agent operating Reply.io, regardless of access layer: ```text theme={null} You operate the Reply.io sales-engagement platform. Rules: 1. One platform, four surfaces (API, MCP, CLI, Skills) — same objects everywhere: contacts, lists, sequences (with steps and variants), inbox threads, tasks, and Jason AI SDR objects (knowledge bases, offers, playbooks, approval queue). 2. Resolve before you mutate: look up exact IDs with search/list operations first. Never invent an ID and never ask the user for one — users don't know internal IDs. 3. High-stakes actions require explicit user confirmation BEFORE executing: sending any message, approving drafts, starting sequences, enrolling contacts, blacklisting, changing contact owners, deleting, and switching Jason to Autonomous. A successful call executes immediately; there is no undo. 4. Report honestly from per-item results: state exact counts ("imported 48 of 50"), and never claim success for an item the response didn't confirm. 5. On timeouts of send-like operations, verify state with a read before retrying — the operation may have already succeeded. 6. Respect rate limits: honor Retry-After on 429, back off on 5xx, paginate lists. 7. If a capability seems missing, check the docs (docs.reply.io) before concluding; prefer the REST API for anything not exposed on your surface. ``` ## MCP variant For agents connected to the [Reply MCP server](/mcp/overview), use the canonical MCP prompt — it adds tool-annotation gating, response-envelope parsing, and the MCP-specific failure guidance: The canonical prompt for MCP agents, maintained with the MCP docs. ## CLI variant For coding agents that shell out to the [`reply` CLI](/cli/overview): ```text theme={null} You operate Reply.io through the `reply` CLI. Rules: 1. The CLI covers authentication and identity (auth, profile, team). Everything else goes through `reply api ` — a raw authenticated call to a v3 endpoint, e.g. `reply api /v3/sequences`. Use paths exactly as documented, starting with /v3; the query string goes in the path. 2. Always pass --json. Data arrives on stdout, status/errors on stderr. 3. `reply api` prints {"code":,"data":} for every status and exits 1 on >= 400 — branch on .code and read .data for the problem details. Other commands print errors as one stderr line: {"error":{status,code,title,detail,hint}}. Act on `hint`. 4. Exit codes: 0 = success, 1 = API/runtime error, 2 = usage error. 5. There is NO --dry-run and NO confirmation prompt. `reply api` sends exactly what you give it. Before any write — POST/PUT/PATCH/DELETE, starting a sequence, sending a reply — show the user the exact request and get explicit approval first. 6. A --body switches the method to POST; override with --method. Bodies accept inline JSON, @file, or - for stdin. 7. Paginate with the endpoint's own parameters (usually top/skip) and keep going while the response has hasMore: true. 8. Rate limits and transient 5xx are retried by the CLI (Retry-After, backoff) — do not add your own retry loop around writes; verify state with a GET instead. 9. Resolve IDs with a GET before mutating — never invent numeric IDs. 10. If a call fails with TEAM_REQUIRED, run `reply team list`, ask the user which workspace to act in, then `reply team use ` or pass --team-id. ``` ## When to hand the agent a Skill instead If your agent platform supports skills (e.g. Claude Code), install the [Reply Agent Skill](/skills/overview) rather than writing procedure into the prompt — it packages the workflows above with verification steps and confirmation gates, and stays updated with the CLI. Keep the CLI variant prompt as a fallback for platforms without skill support. # Agent safety rules Source: https://docs.reply.io/agents/safety Cross-surface safety for agents operating Reply.io — high-stakes gating, scoped keys, and rate-limit etiquette. An agent operating Reply.io can send real messages to real prospects. A successful call executes immediately — there is no undo. These rules apply across all four access layers. ## What counts as high-stakes Confirm with the user before any action that: * **Sends to a prospect** — inbox replies, approving Jason drafts, one-off outreach actions * **Starts outreach** — starting a sequence, enrolling contacts into a sequence * **Changes ownership or reach** — reassigning contacts, blacklisting an email or a whole domain * **Removes work irreversibly** — rejecting a Jason draft (this also removes the contact from the sequence), deleting contacts or lists * **Removes supervision** — switching Jason from Review to Autonomous mode Configuration changes (assigning mailboxes, schedules, attaching offers/playbooks) are production-affecting but not prospect-visible — usually worth confirming too. ## How each surface enforces it | Surface | Mechanism | | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **MCP** | Every tool is annotated in `tools/list`: `readOnlyHint` (31 tools) or `destructiveHint` (39). Gate on these before adding your own confirmation UX. See the [tool contract](/mcp/tool-contract) and the [high-stakes list](/mcp/agent-guide#high-stakes-tools). | | **CLI** | No built-in gating — `reply api` sends exactly the request it is given. The caller owns the confirmation step: show the exact request, get approval, then run it. See [Using the CLI from agents](/cli/agents). | | **Skills** | Every workflow ships with hard confirmation gates — nothing sends, starts, or deletes without explicit approval — plus previews and verification steps. See [Skills](/skills/overview). | | **API** | No built-in gating — your integration is the gate. Use scoped keys (below) to bound the blast radius, and verify state with a read before retrying any timed-out write. | A timed-out send may already have succeeded server-side — on any surface. Verify with a read before retrying anything that reaches a prospect. ## Scoped keys bound the blast radius API keys support granular `domain:verb` scopes (`contacts:read`, `sequences:operate`, `inbox:write`, …) that behave identically on every surface — a key with `sequences:read` can list sequences but not start them, whether the call arrives via REST, MCP, or the CLI. Give an agent the narrowest scope that covers its job; issue separate keys for separate agents so one can be revoked without stopping the others. Details: [Authentication](/api-reference/authentication). ## Rate-limit etiquette One budget covers all surfaces — see [Rate limits](/api-reference/rate-limits). * Honor `Retry-After` on `429`; back off exponentially on `5xx`. (The [CLI](/cli/agents) and MCP server handle this for you.) * Paginate instead of hammering: `top`/`skip` on MCP, and the endpoint's own paging parameters (usually `top`/`skip`) when calling through REST or `reply api`. * Never auto-retry a send, approval, start, or enrollment — verify first (see the [safe-retry matrix](/mcp/tool-contract#safe-retry-matrix); the same logic applies to REST and CLI). ## Report honestly Batch operations return per-item results (`NotProcessed`, `AffectedContactIds`, per-row import failures). Read them and report exact counts — "reassigned 48 of 50" — and never claim an item succeeded unless the response says so. ## Next * [Drop-in system prompts](/agents/prompts) — these rules, pre-packaged for your agent * [MCP tool contract](/mcp/tool-contract) — envelopes, error codes, and the retry matrix in detail # Create an account list Source: https://docs.reply.io/api-reference/account-lists/create-an-account-list /api-reference/bundled.yaml post /v3/contact-account-lists _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates a new account list for the current user's team. Names must be 3–128 characters and unique per team. # Delete an account list Source: https://docs.reply.io/api-reference/account-lists/delete-an-account-list /api-reference/bundled.yaml delete /v3/contact-account-lists/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes an existing account list. The accounts themselves are not deleted — only their membership in this list is removed. # Get an account list Source: https://docs.reply.io/api-reference/account-lists/get-an-account-list /api-reference/bundled.yaml get /v3/contact-account-lists/{id} _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a single account list by ID. # List account lists Source: https://docs.reply.io/api-reference/account-lists/list-account-lists /api-reference/bundled.yaml get /v3/contact-account-lists _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a paginated list of account lists for the current user's team. # Move accounts to an account list Source: https://docs.reply.io/api-reference/account-lists/move-accounts-to-an-account-list /api-reference/bundled.yaml post /v3/contact-account-lists/{id}/move-accounts _Requires the `contacts:operate` scope (or a broader one that includes it)._ Moves accounts to the specified account list, removing them from any other lists they belong to. This is a non-atomic operation: successfully moved accounts are not rolled back if some fail. The response contains only the failed items with their error details. # Update an account list Source: https://docs.reply.io/api-reference/account-lists/update-an-account-list /api-reference/bundled.yaml put /v3/contact-account-lists/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Updates an existing account list name. Names must be 3–128 characters and unique per team. # Bulk add contacts to an account Source: https://docs.reply.io/api-reference/accounts/bulk-add-contacts-to-an-account /api-reference/bundled.yaml post /v3/contact-accounts/{id}/contact-links/bulk _Requires the `contacts:operate` scope (or a broader one that includes it)._ Adds multiple contacts to the specified account. Non-atomic — some may succeed while others fail. Items not in the response dictionary succeeded. # Bulk create accounts Source: https://docs.reply.io/api-reference/accounts/bulk-create-accounts /api-reference/bundled.yaml post /v3/contact-accounts/bulk _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates multiple accounts. Non-atomic — some may succeed while others fail. Each item in the response array contains the created ID or error details. # Bulk delete accounts Source: https://docs.reply.io/api-reference/accounts/bulk-delete-accounts /api-reference/bundled.yaml post /v3/contact-accounts/bulk-delete _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes multiple accounts by ID. Non-atomic — some may succeed while others fail. Items not in the response dictionary succeeded. # Bulk remove contacts from an account Source: https://docs.reply.io/api-reference/accounts/bulk-remove-contacts-from-an-account /api-reference/bundled.yaml post /v3/contact-accounts/{id}/contact-links/bulk-delete _Requires the `contacts:operate` scope (or a broader one that includes it)._ Removes multiple contacts from the specified account. Non-atomic — some may succeed while others fail. Items not in the response dictionary succeeded. # Create an account Source: https://docs.reply.io/api-reference/accounts/create-an-account /api-reference/bundled.yaml post /v3/contact-accounts _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates a new account. # Delete an account Source: https://docs.reply.io/api-reference/accounts/delete-an-account /api-reference/bundled.yaml delete /v3/contact-accounts/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes an existing account. # Filter accounts Source: https://docs.reply.io/api-reference/accounts/filter-accounts /api-reference/bundled.yaml post /v3/contact-accounts/filter _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a paginated, filtered list of accounts using advanced filter criteria. # Get an account Source: https://docs.reply.io/api-reference/accounts/get-an-account /api-reference/bundled.yaml get /v3/contact-accounts/{id} _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a single account by ID. # List accounts Source: https://docs.reply.io/api-reference/accounts/list-accounts /api-reference/bundled.yaml get /v3/contact-accounts _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a paginated list of accounts. # List contacts for an account Source: https://docs.reply.io/api-reference/accounts/list-contacts-for-an-account /api-reference/bundled.yaml get /v3/contact-accounts/{id}/contacts _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a paginated list of contacts linked to the specified account. # Update account owner Source: https://docs.reply.io/api-reference/accounts/update-account-owner /api-reference/bundled.yaml put /v3/contact-accounts/{id}/owner _Requires the `contacts:write` scope (or a broader one that includes it)._ Changes the owner of an account. The new owner must be a member of the caller's team — an `ownerUserId` outside the team returns 400 `contactAccount.invalidInput` (404 is reserved for "account row missing"). # Update an account Source: https://docs.reply.io/api-reference/accounts/update-an-account /api-reference/bundled.yaml put /v3/contact-accounts/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Updates an existing account. # Get AI insights for a contact Source: https://docs.reply.io/api-reference/ai-sdr-insights/get-ai-insights-for-a-contact /api-reference/bundled.yaml get /v3/sequences/ai-sdr/{sequence_id}/contacts/{contact_id}/ai-insights **Coming soon.** This endpoint will be available by late August 2026. Returns the AI-generated insights summary for a single (sequence, contact) pair. The summary is rendered as Markdown. Only available after at least one personalized message has been generated for the contact in this sequence. Returns `404` otherwise. Requires the AI SDR feature on the caller's team. # Industries typeahead Source: https://docs.reply.io/api-reference/ai-sdr-intent-signals/industries-typeahead /api-reference/bundled.yaml get /v3/ai-sdr/intent-signals/industries **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of Reply industry IDs used in intent-signal configuration (e.g. `technologyUsed.industryId`, `jobHiring.industries[]`). Distinct taxonomy from the Live Data filter-value industries — those are string-only Sales Navigator industries. Requires the AI SDR feature on the caller's team. # Technologies typeahead Source: https://docs.reply.io/api-reference/ai-sdr-intent-signals/technologies-typeahead /api-reference/bundled.yaml get /v3/ai-sdr/intent-signals/technologies **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of Reply technology slugs used in intent-signal configuration (e.g. `technologyUsed.technologies[]`). The slug is the persisted identifier; name is display-only. Requires the AI SDR feature on the caller's team. # Add a link Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/add-a-link /api-reference/bundled.yaml post /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/links _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Adds a web link to a knowledge base. Requires the AI SDR feature on the caller's team. # Create a knowledge base Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/create-a-knowledge-base /api-reference/bundled.yaml post /v3/ai-sdr/knowledge-bases _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Creates a new knowledge base. Only `name` is required. Requires the AI SDR feature on the caller's team. # Create a reengagement card Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/create-a-reengagement-card /api-reference/bundled.yaml post /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reengagement-cards **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Creates a new reengagement card attached to a knowledge base. Requires the AI SDR feature on the caller's team. # Create a reply handler Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/create-a-reply-handler /api-reference/bundled.yaml post /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reply-handlers **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Creates a new reply handler attached to a knowledge base. Requires the AI SDR feature on the caller's team. # Delete a document Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/delete-a-document /api-reference/bundled.yaml delete /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/documents/{document_id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Removes a document from a knowledge base. Requires the AI SDR feature on the caller's team. # Delete a knowledge base Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/delete-a-knowledge-base /api-reference/bundled.yaml delete /v3/ai-sdr/knowledge-bases/{id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Deletes a knowledge base. Requires the AI SDR feature on the caller's team. # Delete a link Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/delete-a-link /api-reference/bundled.yaml delete /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/links/{link_id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Removes a link from a knowledge base. Requires the AI SDR feature on the caller's team. # Delete a reengagement card Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/delete-a-reengagement-card /api-reference/bundled.yaml delete /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reengagement-cards/{reengagement_card_id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Deletes a reengagement card. Requires the AI SDR feature on the caller's team. # Delete a reply handler Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/delete-a-reply-handler /api-reference/bundled.yaml delete /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reply-handlers/{reply_handler_id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Deletes a reply handler. Requires the AI SDR feature on the caller's team. # Delete reengagement card media Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/delete-reengagement-card-media /api-reference/bundled.yaml delete /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reengagement-cards/{reengagement_card_id}/media/{media_id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Removes a media item from a reengagement card. Requires the AI SDR feature on the caller's team. # Delete reply handler media Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/delete-reply-handler-media /api-reference/bundled.yaml delete /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reply-handlers/{reply_handler_id}/media/{media_id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Removes a media item from a reply handler. Requires the AI SDR feature on the caller's team. # Duplicate a knowledge base Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/duplicate-a-knowledge-base /api-reference/bundled.yaml post /v3/ai-sdr/knowledge-bases/{id}/duplicate _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Creates a copy of an existing knowledge base, including its links, documents, reply handlers, and reengagement cards. Requires the AI SDR feature on the caller's team. # Get a knowledge base Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/get-a-knowledge-base /api-reference/bundled.yaml get /v3/ai-sdr/knowledge-bases/{id} _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a single knowledge base by id. Requires the AI SDR feature on the caller's team. # Get a reengagement card Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/get-a-reengagement-card /api-reference/bundled.yaml get /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reengagement-cards/{reengagement_card_id} **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a single reengagement card by id. Requires the AI SDR feature on the caller's team. # Get a reply handler Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/get-a-reply-handler /api-reference/bundled.yaml get /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reply-handlers/{reply_handler_id} **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a single reply handler by id. Requires the AI SDR feature on the caller's team. # List documents Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/list-documents /api-reference/bundled.yaml get /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/documents _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of file documents attached to a knowledge base. Requires the AI SDR feature on the caller's team. # List knowledge bases Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/list-knowledge-bases /api-reference/bundled.yaml get /v3/ai-sdr/knowledge-bases _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of knowledge bases visible to the caller. Requires the AI SDR feature on the caller's team. # List links Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/list-links /api-reference/bundled.yaml get /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/links _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of web links attached to a knowledge base. Requires the AI SDR feature on the caller's team. # List reengagement cards Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/list-reengagement-cards /api-reference/bundled.yaml get /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reengagement-cards **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of reengagement cards attached to a knowledge base. Requires the AI SDR feature on the caller's team. # List reply handlers Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/list-reply-handlers /api-reference/bundled.yaml get /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reply-handlers **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of reply handlers attached to a knowledge base. Requires the AI SDR feature on the caller's team. # Update a knowledge base Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/update-a-knowledge-base /api-reference/bundled.yaml patch /v3/ai-sdr/knowledge-bases/{id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Partial update — send only the fields you want to change. At least one field must be present. Requires the AI SDR feature on the caller's team. # Update a reengagement card Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/update-a-reengagement-card /api-reference/bundled.yaml patch /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reengagement-cards/{reengagement_card_id} **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Partial update — send only the fields you want to change. At least one field must be present. Media is not patched here; use the `/media` sub-resource. Requires the AI SDR feature on the caller's team. # Update a reply handler Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/update-a-reply-handler /api-reference/bundled.yaml patch /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reply-handlers/{reply_handler_id} **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Partial update — send only the fields you want to change. At least one field must be present. Media is not patched here; use the `/media` sub-resource. Requires the AI SDR feature on the caller's team. # Upload a document Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/upload-a-document /api-reference/bundled.yaml post /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/documents _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Uploads a file document to a knowledge base. Maximum upload size: 100 MB. Requires the AI SDR feature on the caller's team. # Upload reengagement card media Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/upload-reengagement-card-media /api-reference/bundled.yaml post /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reengagement-cards/{reengagement_card_id}/media _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Attaches a media file to a reengagement card. Maximum upload size: 100 MB. Requires the AI SDR feature on the caller's team. # Upload reply handler media Source: https://docs.reply.io/api-reference/ai-sdr-knowledge-bases/upload-reply-handler-media /api-reference/bundled.yaml post /v3/ai-sdr/knowledge-bases/{knowledge_base_id}/reply-handlers/{reply_handler_id}/media _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Attaches a media file to a reply handler. Maximum upload size: 100 MB. Requires the AI SDR feature on the caller's team. # Create an offer Source: https://docs.reply.io/api-reference/ai-sdr-offers/create-an-offer /api-reference/bundled.yaml post /v3/ai-sdr/offers _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Creates a new offer. Only `name` is strictly required; all other fields default to empty. Requires the AI SDR feature on the caller's team. # Delete an offer Source: https://docs.reply.io/api-reference/ai-sdr-offers/delete-an-offer /api-reference/bundled.yaml delete /v3/ai-sdr/offers/{id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Deletes an offer. Requires the AI SDR feature on the caller's team. # Duplicate an offer Source: https://docs.reply.io/api-reference/ai-sdr-offers/duplicate-an-offer /api-reference/bundled.yaml post /v3/ai-sdr/offers/{id}/duplicate **Coming soon.** This endpoint will be available by early August 2026. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Creates a copy of an existing offer, including its company-context fields (ICP, reason for outreach, case studies, pain points, proof points, value propositions, and calls to action). The copy is returned in the response body. Requires the AI SDR feature on the caller's team. # Generate an offer Source: https://docs.reply.io/api-reference/ai-sdr-offers/generate-an-offer /api-reference/bundled.yaml post /v3/ai-sdr/offers/generate **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Generates an offer from a prompt or company URL, optionally seeded with previously uploaded attachments. The generated offer is persisted directly — clients do not need a separate create call. Returns a background job to poll via `GET /v3/background-jobs/{jobId}`; on completion its `jsonDataResult` carries the generated offer (`offerId` plus the same company-context fields returned by `GET /v3/ai-sdr/offers/{id}`). Requires the AI SDR feature on the caller's team. # Get an offer Source: https://docs.reply.io/api-reference/ai-sdr-offers/get-an-offer /api-reference/bundled.yaml get /v3/ai-sdr/offers/{id} _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a single offer by id. Requires the AI SDR feature on the caller's team. # List offers Source: https://docs.reply.io/api-reference/ai-sdr-offers/list-offers /api-reference/bundled.yaml get /v3/ai-sdr/offers _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of offers visible to the caller. Requires the AI SDR feature on the caller's team. # Update an offer Source: https://docs.reply.io/api-reference/ai-sdr-offers/update-an-offer /api-reference/bundled.yaml patch /v3/ai-sdr/offers/{id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Partial update — send only the fields you want to change. Array fields, if present, fully replace the current value (no item-level merge). At least one field must be present. Requires the AI SDR feature on the caller's team. # Upload an attachment for offer generation Source: https://docs.reply.io/api-reference/ai-sdr-offers/upload-an-attachment-for-offer-generation /api-reference/bundled.yaml post /v3/ai-sdr/offers/generation-attachments **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Uploads a single attachment whose id can be passed in `attachmentIds` of `POST /v3/ai-sdr/offers/generate` to seed the generation. Maximum size 10 MB; supported formats are `.txt`, `.pdf`, `.doc`, `.docx`, and `.rtf`. Requires the AI SDR feature on the caller's team. # Get pending approval for a contact Source: https://docs.reply.io/api-reference/ai-sdr-pending-approvals/get-pending-approval-for-a-contact /api-reference/bundled.yaml get /v3/sequences/ai-sdr/{sequence_id}/contacts/{contact_id}/approval **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns the pending AI-generated message for a single (sequence, contact) pair, including the prior message thread for context. Requires the AI SDR feature on the caller's team. # List pending approvals Source: https://docs.reply.io/api-reference/ai-sdr-pending-approvals/list-pending-approvals /api-reference/bundled.yaml get /v3/ai-sdr/approvals **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of AI-generated messages awaiting human approval before being sent. Requires the AI SDR feature on the caller's team. # Regenerate a pending approval Source: https://docs.reply.io/api-reference/ai-sdr-pending-approvals/regenerate-a-pending-approval /api-reference/bundled.yaml post /v3/sequences/ai-sdr/{sequence_id}/contacts/{contact_id}/approval/regenerate **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Starts a background job that regenerates the AI-generated message for a single (sequence, contact) pair, and returns the job id. Optionally pass freeform `recommendations` to steer the regeneration. Poll `GET /v3/background-jobs/{jobId}` for status; when the job finishes, its result holds the regenerated `subject` and `body`. Requires the AI SDR feature on the caller's team. # Reject (delete) a pending approval Source: https://docs.reply.io/api-reference/ai-sdr-pending-approvals/reject-delete-a-pending-approval /api-reference/bundled.yaml delete /v3/sequences/ai-sdr/{sequence_id}/contacts/{contact_id}/approval **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Discards the pending AI-generated message for a contact and removes the contact from the sequence. The queued draft and its personalization step are deleted. Requires the AI SDR feature on the caller's team. # Send a batch of pending approvals Source: https://docs.reply.io/api-reference/ai-sdr-pending-approvals/send-a-batch-of-pending-approvals /api-reference/bundled.yaml post /v3/ai-sdr/approvals/send-bulk **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Approves and sends the queued AI-generated messages for up to 20 (sequence, contact) pairs in one call. Bodies and subjects cannot be overridden in bulk — use the per-contact endpoint for that. Requires the AI SDR feature on the caller's team. # Send a pending approval Source: https://docs.reply.io/api-reference/ai-sdr-pending-approvals/send-a-pending-approval /api-reference/bundled.yaml post /v3/sequences/ai-sdr/{sequence_id}/contacts/{contact_id}/approval/send **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Approves and sends the queued AI-generated message for a single (sequence, contact) pair. Optionally override the draft body and/or subject before sending. Requires the AI SDR feature on the caller's team. # Submit feedback on a pending approval Source: https://docs.reply.io/api-reference/ai-sdr-pending-approvals/submit-feedback-on-a-pending-approval /api-reference/bundled.yaml post /v3/sequences/ai-sdr/{sequence_id}/contacts/{contact_id}/approval/feedback **Coming soon.** This endpoint will be available by late August 2026. Records a thumbs-up / thumbs-down reaction on the queued AI-generated message, with optional dislike reasons and a freeform comment. Used as a training signal for the AI SDR. No step identifier is needed — the approval is unique per (sequence, contact). Requires the AI SDR feature on the caller's team. # Create a playbook Source: https://docs.reply.io/api-reference/ai-sdr-playbooks/create-a-playbook /api-reference/bundled.yaml post /v3/ai-sdr/playbooks _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Creates a new playbook in the `organization` or `team` scope. `global` playbooks are Reply-curated and cannot be created via the API. Requires the AI SDR feature on the caller's team. # Delete a playbook Source: https://docs.reply.io/api-reference/ai-sdr-playbooks/delete-a-playbook /api-reference/bundled.yaml delete /v3/ai-sdr/playbooks/{id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Deletes a playbook. `global` playbooks cannot be deleted via the API. Requires the AI SDR feature on the caller's team. # Delete a style file Source: https://docs.reply.io/api-reference/ai-sdr-playbooks/delete-a-style-file /api-reference/bundled.yaml delete /v3/ai-sdr/playbooks/{playbook_id}/style-files/{style_file_id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Removes a style file from a playbook. Requires the AI SDR feature on the caller's team. # Duplicate a playbook Source: https://docs.reply.io/api-reference/ai-sdr-playbooks/duplicate-a-playbook /api-reference/bundled.yaml post /v3/ai-sdr/playbooks/{id}/duplicate **Coming soon.** This endpoint will be available by early August 2026. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Creates a copy of an existing playbook and returns the new playbook in the response body. `global` playbooks can also be duplicated. Requires the AI SDR feature on the caller's team. # Get a playbook Source: https://docs.reply.io/api-reference/ai-sdr-playbooks/get-a-playbook /api-reference/bundled.yaml get /v3/ai-sdr/playbooks/{id} _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a single playbook by its composite id (`g-N` / `o-N` / `t-N`). Requires the AI SDR feature on the caller's team. # List playbooks Source: https://docs.reply.io/api-reference/ai-sdr-playbooks/list-playbooks /api-reference/bundled.yaml get /v3/ai-sdr/playbooks _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns a paginated list of playbooks visible to the caller. When `type` is omitted, results from all three scopes (`global`, `organization`, `team`) are merged. Requires the AI SDR feature on the caller's team. # Update a playbook Source: https://docs.reply.io/api-reference/ai-sdr-playbooks/update-a-playbook /api-reference/bundled.yaml patch /v3/ai-sdr/playbooks/{id} _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Partial update — send only the fields you want to change. `type` is immutable. Requires the AI SDR feature on the caller's team. # Upload a style file Source: https://docs.reply.io/api-reference/ai-sdr-playbooks/upload-a-style-file /api-reference/bundled.yaml post /v3/ai-sdr/playbooks/{playbook_id}/style-files _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Uploads a style file (reference document) to a playbook. Style files inform tone and voice when the playbook is applied. Maximum upload size: 100 MB. Requires the AI SDR feature on the caller's team. # Personalize the preview for a contact Source: https://docs.reply.io/api-reference/ai-sdr-sequence-preview/personalize-the-preview-for-a-contact /api-reference/bundled.yaml post /v3/sequences/ai-sdr/{sequence_id}/contacts/{contact_id}/preview/personalize **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Kicks off (or re-runs) AI personalization for a single contact in an AI SDR sequence. Personalization runs step-by-step in the background. The whole step chain for the contact is tracked by a single background job: the response returns its `jobId`, and progress advances as `personalizedSteps / totalSteps`. Poll the generic `GET /v3/background-jobs/{id}` endpoint for status and progress; on completion the job's `jsonDataResult` carries `{ sequenceId, contactId, personalizedSteps, totalSteps }`. A chain that ended early (for example, the contact was removed mid-chain) reports `personalizedSteps < totalSteps`. Requires the AI SDR feature on the caller's team. # Submit feedback on a preview step Source: https://docs.reply.io/api-reference/ai-sdr-sequence-preview/submit-feedback-on-a-preview-step /api-reference/bundled.yaml post /v3/sequences/ai-sdr/{sequence_id}/contacts/{contact_id}/preview/steps/{step_id}/feedback **Coming soon.** This endpoint will be available by late August 2026. Records a thumbs-up / thumbs-down reaction on the AI-generated message for a specific step in a contact's preview, with optional dislike reasons and a freeform comment. Used as a training signal for the AI SDR. Requires the AI SDR feature on the caller's team. # Attach a playbook to the sequence Source: https://docs.reply.io/api-reference/ai-sdr-sequences/attach-a-playbook-to-the-sequence /api-reference/bundled.yaml put /v3/sequences/ai-sdr/{sequence_id}/playbook **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:operate` scope (or a broader one that includes it)._ Attaches a playbook to the sequence by composite id. Replaces any previously-attached playbook. Requires the AI SDR feature on the caller's team. # Connect a knowledge base to the sequence Source: https://docs.reply.io/api-reference/ai-sdr-sequences/connect-a-knowledge-base-to-the-sequence /api-reference/bundled.yaml put /v3/sequences/ai-sdr/{sequence_id}/knowledge-base **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:operate` scope (or a broader one that includes it)._ Connects a knowledge base to the sequence by id. Replaces any previously-connected knowledge base. Requires the AI SDR feature on the caller's team. # Create an AI SDR sequence Source: https://docs.reply.io/api-reference/ai-sdr-sequences/create-an-ai-sdr-sequence /api-reference/bundled.yaml post /v3/sequences/ai-sdr **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Creates a new AI SDR sequence with its full AI SDR settings payload. The sequence is seeded either from a saved offer (`offerId`) or from inline offer-context inputs (`offerGenerationInputs`) — exactly one is required. Sequence steps are generated by the AI SDR — clients do not pass `steps` here. Generic sequence fields (`name`, `scheduleId`, `settings`, `emailAccounts`, `linkedInAccounts`) are accepted and applied after the AI SDR-specific setup. Requires the AI SDR feature on the caller's team. # Detach the playbook from the sequence Source: https://docs.reply.io/api-reference/ai-sdr-sequences/detach-the-playbook-from-the-sequence /api-reference/bundled.yaml delete /v3/sequences/ai-sdr/{sequence_id}/playbook **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:operate` scope (or a broader one that includes it)._ Detaches the playbook attached to the sequence. Returns 404 if no playbook is attached. Requires the AI SDR feature on the caller's team. # Disable autopilot Source: https://docs.reply.io/api-reference/ai-sdr-sequences/disable-autopilot /api-reference/bundled.yaml post /v3/sequences/ai-sdr/{sequence_id}/autopilot/disable **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:operate` scope (or a broader one that includes it)._ Disables autopilot on the sequence. No-op when autopilot is already disabled. Requires the AI SDR feature on the caller's team. # Disconnect the knowledge base from the sequence Source: https://docs.reply.io/api-reference/ai-sdr-sequences/disconnect-the-knowledge-base-from-the-sequence /api-reference/bundled.yaml delete /v3/sequences/ai-sdr/{sequence_id}/knowledge-base **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:operate` scope (or a broader one that includes it)._ Disconnects the knowledge base connected to the sequence. Returns 404 if no knowledge base is connected. Requires the AI SDR feature on the caller's team. # Enable autopilot Source: https://docs.reply.io/api-reference/ai-sdr-sequences/enable-autopilot /api-reference/bundled.yaml post /v3/sequences/ai-sdr/{sequence_id}/autopilot/enable **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:operate` scope (or a broader one that includes it)._ Enables autopilot on the sequence. No-op when autopilot is already enabled. Requires the AI SDR feature on the caller's team. # Force-start an autopilot search Source: https://docs.reply.io/api-reference/ai-sdr-sequences/force-start-an-autopilot-search /api-reference/bundled.yaml post /v3/sequences/ai-sdr/{sequence_id}/autopilot/force-start **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:operate` scope (or a broader one that includes it)._ Force-starts an autopilot contact search for the sequence, bypassing the normal schedule. Autopilot must already be enabled; rejected with 409 otherwise. Requires the AI SDR feature on the caller's team. # Get the sequence's knowledge base Source: https://docs.reply.io/api-reference/ai-sdr-sequences/get-the-sequences-knowledge-base /api-reference/bundled.yaml get /v3/sequences/ai-sdr/{sequence_id}/knowledge-base **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns the knowledge base connected to the sequence. Each sequence is connected to at most one knowledge base. Requires the AI SDR feature on the caller's team. # Get the sequence's playbook Source: https://docs.reply.io/api-reference/ai-sdr-sequences/get-the-sequences-playbook /api-reference/bundled.yaml get /v3/sequences/ai-sdr/{sequence_id}/playbook **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns the playbook attached to the sequence. Each sequence is attached to at most one playbook. Requires the AI SDR feature on the caller's team. # Preview autopilot results Source: https://docs.reply.io/api-reference/ai-sdr-sequences/preview-autopilot-results /api-reference/bundled.yaml post /v3/sequences/ai-sdr/{sequence_id}/autopilot/preview **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:operate` scope (or a broader one that includes it)._ Previews the expected autopilot results for the sequence. Clients pass the autopilot filter config in the body — they are NOT required to save it to the sequence first (supports try-before-save in the filter UI). Returns a background job to poll via `GET /v3/background-jobs/{id}`; on completion its `jsonDataResult` carries `{ contactsCount, companiesCount, sampleContacts }`, where `sampleContacts` is a capped sample of matching contacts. Requires the AI SDR feature on the caller's team. # Read AI SDR sequence settings Source: https://docs.reply.io/api-reference/ai-sdr-sequences/read-ai-sdr-sequence-settings /api-reference/bundled.yaml get /v3/sequences/ai-sdr/{sequence_id}/settings **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:read` scope (or a broader one that includes it)._ Returns the AI SDR-specific settings of a sequence. Mirrors the shape of the create/patch body. Generic sequence fields (name, schedule, etc.) are read via `GET /v3/sequences/{id}`. Requires the AI SDR feature on the caller's team. # Set generated step types Source: https://docs.reply.io/api-reference/ai-sdr-sequences/set-generated-step-types /api-reference/bundled.yaml put /v3/sequences/ai-sdr/{sequence_id}/generated-step-types **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Replaces the step channels the AI SDR is allowed to generate, and triggers regeneration of the sequence's steps using the new mix. Rejected with 409 once the sequence has already acted on contacts (sent emails or LinkedIn messages, generated tasks, etc.). Requires the AI SDR feature on the caller's team. # Set the approval mode Source: https://docs.reply.io/api-reference/ai-sdr-sequences/set-the-approval-mode /api-reference/bundled.yaml put /v3/sequences/ai-sdr/{sequence_id}/approval-mode **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:operate` scope (or a broader one that includes it)._ Sets the sequence's approval mode — whether AI-generated messages require human approval before sending. Settable only via this dedicated PUT (or at create time); NOT in the AI SDR sequence PATCH. When disabling (`enabled` = `false`), `approveAllPendingContacts` may be set to `true` to immediately approve all currently-pending contacts. `approveAllPendingContacts` is rejected when enabling. Requires the AI SDR feature on the caller's team. # Update AI SDR sequence settings Source: https://docs.reply.io/api-reference/ai-sdr-sequences/update-ai-sdr-sequence-settings /api-reference/bundled.yaml patch /v3/sequences/ai-sdr/{sequence_id}/settings **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Partial update of AI SDR-specific sequence settings (generation inputs, tone of voice, personalization points, provider LLM, autopilot config, intent signals). PATCH semantics: a field absent from the body is skipped; a field explicitly set to `null` is rejected. `intentSignals`, when present, fully replaces the current list. `autopilot.filters`, when present, fully replaces the current filters object. At least one field must be present. Out of scope for this PATCH (use the dedicated sub-resources instead): name and other generic sequence fields, approval mode, generated step types, attached playbook, connected knowledge base. Requires the AI SDR feature on the caller's team. # Start a strategist run Source: https://docs.reply.io/api-reference/ai-sdr-strategist/start-a-strategist-run /api-reference/bundled.yaml post /v3/ai-sdr/strategist/start **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `ai-sdr:write` scope (or a broader one that includes it)._ Starts an AI Strategist run for the caller's team. The strategist generates sequence ideas and creates a sequence for each one. Returns a background job to poll via `GET /v3/background-jobs/{jobId}`; on completion its `jsonDataResult` carries `{ sequenceIds }` — the ids of the sequences created from the generated ideas. Requires the AI SDR feature on the caller's team. # List AI web searches for a sequence Source: https://docs.reply.io/api-reference/ai-sdr-web-search/list-ai-web-searches-for-a-sequence /api-reference/bundled.yaml get /v3/ai-web-search/searches **Coming soon.** This endpoint will be available by late August 2026. Returns AI web searches started for a given sequence. # Start an AI web search Source: https://docs.reply.io/api-reference/ai-sdr-web-search/start-an-ai-web-search /api-reference/bundled.yaml post /v3/ai-web-search/start **Coming soon.** This endpoint will be available by late August 2026. Kicks off an AI-driven web search to find contacts for a sequence. # Authentication Source: https://docs.reply.io/api-reference/authentication Learn how to authenticate requests and manage API keys. The Reply API uses Bearer token authentication. Every request must include your API key in the `Authorization` header. ## Get your API key Sign in to your [Reply.io dashboard](https://run.reply.io). Go to **Settings → API Key**. Create a new API key or copy an existing one. Treat your API key like a password. ## Authenticate a request Include your API key as a Bearer token: ```http theme={null} GET /v3/whoami HTTP/1.1 Host: api.reply.io Authorization: Bearer YOUR_API_KEY ``` ### curl example ```bash theme={null} curl https://api.reply.io/v3/whoami \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Verify your setup Call `/v3/whoami` to verify that your API key works. A successful response returns information about the authenticated user: ```json theme={null} { "userId": 12345 } ``` ## Unauthorized response If the `Authorization` header is missing, invalid, or contains a revoked API key, the API returns `401 Unauthorized` with an empty response body. The response includes a `WWW-Authenticate` header: ```text theme={null} HTTP/1.1 401 Unauthorized Content-Length: 0 WWW-Authenticate: Bearer ``` Do not expect a JSON error response. Use the status code and headers to handle authentication failures. This empty-body `401` covers **key** failures — a missing, malformed, or revoked key. A request that presents a valid Team or Organization key but cannot resolve an acting user is different: it returns an `application/problem+json` body with a `code` (see [Organization API key → Rejection responses](#rejection-responses)). ## Scopes Every API key is granted a set of **scopes**. A scope is a permission such as `contacts:read` that controls which endpoints the key can call. Each endpoint requires a single **minimal scope**, shown as a small note near the top of that endpoint's reference description (below any Beta notice) — for example: *Requires the `contacts:read` scope (or a broader one that includes it).* Endpoints that need no particular permission say **No scope required** instead — any valid API key can call them (for example, `GET /v3/whoami`). Scopes are configured **per API key** in **Settings → API Key**. Grant a key only the scopes its integration needs. ### Scope format A scope is written as `domain:verb`: * **`domain`** — the area of the API the permission applies to (for example `contacts`, `sequences`, `inbox`). * **`verb`** — the level of access within that domain: * **`read`** — read data. * **`write`** — create, update, or delete data. * **`operate`** — trigger runtime actions (for example, push a contact to a sequence, start or pause a sequence, or reply to an inbox thread). ### How a key satisfies a required scope A key can hold a required scope directly, or hold a **broader** scope that includes it: * **`write` and `operate` each also satisfy a `read` requirement** — a key that can write or operate in a domain can also read in that domain. (`write` and `operate` are independent of each other; neither one includes the other.) * A **verb wildcard** `domain:*` satisfies any verb in that domain — for example, `contacts:*` satisfies `contacts:read`, `contacts:write`, and `contacts:operate`. * The **global wildcard** `*:*` satisfies every scope. For example, an endpoint that requires `contacts:read` can be called by a key granted any of `contacts:read`, `contacts:write`, `contacts:operate`, `contacts:*`, or `*:*`. ### Available scopes | Domain | Scopes | Covers | | ----------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `settings` | `settings:read`, `settings:write` | Read and modify account settings. | | `contacts` | `contacts:read`, `contacts:write`, `contacts:operate` | Read contacts, accounts, and related data; create/update/delete them; and trigger contact-level runtime actions (push to sequence, enrich, etc.). | | `sequences` | `sequences:read`, `sequences:write`, `sequences:operate` | Read sequences, steps, variants, and templates; create/update/delete them; and start, pause, or resume running sequences. | | `channels` | `channels:read`, `channels:write`, `channels:operate` | Read connected email and LinkedIn channels, manage their configuration, and connect/disconnect/re-authorize them. | | `inbox` | `inbox:read`, `inbox:write`, `inbox:operate` | Read inbox threads, messages, and categories; manage inbox configuration; and reply, mark, or categorize threads. | | `tasks` | `tasks:read`, `tasks:write`, `tasks:operate` | Read tasks, create/update/delete them, and complete or execute them. | | `reporting` | `reporting:read` | Read reporting data. **Read-only** — there is no `write` or `operate` verb. | | `webhooks` | `webhooks:read`, `webhooks:write`, `webhooks:operate` | Read webhook subscriptions and deliveries, manage subscriptions, and test/enable/disable them. | | `ai-sdr` | `ai-sdr:read`, `ai-sdr:write`, `ai-sdr:operate` | Read AI-SDR campaigns and configuration, manage them, and run/stop/manage their runtime state. | | `other` | `other:read`, `other:write`, `other:operate` | Read, manage, or trigger miscellaneous resources not covered by a domain-specific scope (background jobs, etc.). | A separate `legacy:use` scope governs the older, non-V3 API and does not apply to the V3 endpoints documented here. ## Special API keys In addition to user API keys, Reply supports two centralized authentication methods: * **Team keys** for a single team/workspace * **Organization API keys** for all team/workspaces in an organization ### Team key — team level A Team key provides team/workspace-wide access. Unlike a user API key, which always acts as a single user, a Team key can make requests as any user in the team/workspace. Common use cases include: * Team-wide automation * Cross-user reporting * Bulk operations #### Permissions and access control * Only the team/workspace owner can generate and view the Team key. * The key must be created manually. * A Team key is unique to its team/workspace. For a credential that spans every team/workspace in an organization, see [Organization API key](#organization-api-key-—-organization-level) below. #### Acting on behalf of a user Use one of the following headers: * `X-User-Id` * `X-User-Email` You only need one header. #### Behavior and permission model Team keys use the same permission model as user API keys. | Request | Behavior | | ------------------------- | ------------------------------------- | | Team key only | Acts as the team/workspace owner | | Team key + `X-User-Id` | Acts as the specified user (by ID) | | Team key + `X-User-Email` | Acts as the specified user (by email) | In all cases, the permissions of the resolved user are applied. #### Important notes * If an impersonation header is provided, the request runs with that user's permissions. * If no impersonation header is provided, the request runs with the team/workspace owner's permissions. * A Team key does not grant permissions beyond those of the resolved user. ### Organization API key — organization level An **Organization API** key provides centralized access across every team/workspace in an organization. Unlike a Team key, which is limited to a single team/workspace, an Organization API key can act on behalf of users across all team/workspaces owned by the organization. #### Availability * Organization-scoped * Works across all team/workspaces in the organization * Multiple keys can be created * Keys can be named, revoked, and rotated independently #### Permissions and access control By default, Organization Owners can create, view, and revoke organization API keys. Other organization users can be granted role with permission 'Manage organization API keys' to manage organization API keys. Keys are managed in: **Settings → API keys** #### Acting on behalf of a user Organization API keys always require impersonation. Use one of the following: * `X-USER-ID` * `X-User-Email` together with `X-TEAM-ID` If no impersonation header is provided, the request is rejected. If `X-User-Email` is provided without `X-TEAM-ID`, the request is rejected. Example: ```http theme={null} GET /v3/whoami HTTP/1.1 Host: api.reply.io Authorization: Bearer YOUR_ORG_API_KEY X-USER-ID: 12345 ``` #### Behavior and permission model | Request | Behavior | | ----------------------------------------------- | ------------------------------------------------------------ | | Organization key + `X-USER-ID` | Acts as the user with that ID | | Organization key + `X-User-Email` + `X-TEAM-ID` | Acts as the user with that email in the given team/workspace | | Organization key without impersonation | Rejected — `403 USER_REQUIRED` | | User belongs to a different organization | Rejected — `403 TEAM_NOT_ACCESSIBLE` | In all accepted requests, the permissions of the resolved user are applied. #### Rejection responses A rejected impersonation request returns `application/problem+json` with a stable `code` you can branch on: | Condition | Status | `code` | | --------------------------------------------------------------- | ------ | --------------------- | | No impersonation header (or `X-User-Email` without `X-TEAM-ID`) | `403` | `USER_REQUIRED` | | Resolved user does not exist | `401` | `USER_NOT_FOUND` | | Resolved user belongs to a different organization | `403` | `TEAM_NOT_ACCESSIBLE` | ```json theme={null} { "title": "Access forbidden", "status": 403, "code": "USER_REQUIRED", "detail": "This credential requires an acting-user header." } ``` This is distinct from an invalid or expired key, which returns `401` with an empty body (see [Unauthorized response](#unauthorized-response)). #### Important notes * Every request runs with the permissions of the resolved user. * The resolved user must belong to the same organization that issued the key. * An Organization API key does not grant permissions beyond those of the resolved user. ## Keep your API key safe * Never commit API keys to source control. * Never share API keys in public chats or screenshots. * Rotate your API key from **Settings → API Key** if you think it has been exposed. # Introduction Source: https://docs.reply.io/api-reference/introduction Reply is an AI-powered sales engagement platform. The Reply API gives you access to the platform's core features, including contacts, multichannel sequences, the unified inbox, scheduling, reporting, and webhooks. Use it to manage prospecting and outreach from your own systems. Reply is an AI-powered sales engagement platform. The Reply API (v3) gives you access to the platform through a REST API, so you can automate the same workflows available in the Reply dashboard from your own applications, scripts, or AI agents. ## At a glance Every request is an HTTPS call to a `/v3` endpoint and includes your API key in the `Authorization` header. This example returns information about the authenticated user and confirms that your credentials work: ```bash theme={null} curl https://api.reply.io/v3/whoami \ -H "Authorization: Bearer YOUR_API_KEY" ``` * **Base URL**: `https://api.reply.io`, with all endpoints under the `/v3` prefix (for example, `/v3/sequences`). * **Authentication**: Bearer token in the `Authorization` header on every request. * **Format**: JSON request and response bodies. Errors use `application/problem+json`. * **Rate limits**: 100 requests per minute and 3,000 requests per hour, per user. ## What you can do The API covers every major area of the platform. Each area has its own group of endpoints in the API reference. | Area | What you can manage | | ------------------------ | ----------------------------------------------------------------------------- | | **Contacts & data** | Contacts, contact lists, custom fields, and blacklist rules | | **Sequences** | Multichannel sequences across email, LinkedIn, calls, and manual tasks | | **Accounts & templates** | Connected email and LinkedIn accounts, plus shared templates | | **Inbox** | Replies handled through the unified Inbox | | **Scheduling** | Sending schedules and holiday calendars that control send times | | **Tasks** | Manual tasks assigned to your team | | **Reporting** | Performance reports across all channels | | **Automation** | Webhooks for real-time events and background jobs for long-running operations | ## API conventions The API follows consistent patterns across endpoints. ### REST Resource URLs use plural nouns and standard HTTP methods: * `GET` to read * `POST` to create * `PATCH` to update * `DELETE` to remove Request and response bodies use JSON. ### Errors All `4xx` and `5xx` responses use `application/problem+json`. Business errors include a stable code in `.` format, so you can handle them programmatically: ```json theme={null} { "title": "Bad Request", "status": 400, "detail": "Unknown webhook event 'email_clicked'.", "code": "webHook.invalidEvent" } ``` Validation errors (`400 Bad Request`) also include an `errors[]` array. Each entry identifies the invalid field using a JSON Pointer. ### Asynchronous jobs Long-running operations, such as email validation and large bulk imports, return `202 Accepted` with a `Location` header that points to `/v3/background-jobs/{id}`. Use the Background Jobs endpoint to check job status or cancel a job. ## Authentication v3 uses Bearer token authentication. Every request must include an `Authorization: Bearer ` header. If the token is missing, invalid, or revoked, the API returns `401 Unauthorized` with a `WWW-Authenticate: Bearer` header and an empty response body. See **Authentication** for instructions on generating an API key, making your first authenticated request, using Master and Organization keys, and verifying credentials with `/v3/whoami`. ## Rate limits To protect the platform, requests are limited to 100 per minute and 3,000 per hour, per user. When you exceed a limit, the API returns `429 Too Many Requests` and includes a `Retry-After` header that tells you when to retry. Reporting and statistics endpoints have stricter limits. See **Rate Limits** for details. ## Versioning v3 is the current supported version and should be used for all new integrations. API v1 and v2 remain available but are no longer supported and will be deprecated in the future. Their documentation is available at `apidocs.reply.io`. ## Connect an AI agent Reply MCP connects Reply to Claude, Cursor, and other MCP-compatible AI clients, allowing agents to use Reply without making direct HTTP requests. Connect Reply to your AI client. Get an API key and make your first authenticated request. ## Get help Questions, feedback, or stuck on an endpoint? The Reply developer community on Slack is the fastest way to reach us and other builders. Ask questions, share feedback, and discuss the API — no Reply account required. # Rate limits Source: https://docs.reply.io/api-reference/rate-limits Rate limits, 429 responses, and retry guidance. The Reply API limits the number of requests each user can make. When a limit is exceeded, the API returns `429 Too Many Requests`. ## Limits * **100 requests per minute** * **3,000 requests per hour** Limits are applied per user. Requests made by multiple applications, scripts, or services on behalf of the same user count toward the same quota. ## Stricter endpoints Some endpoints have lower hourly limits than the default quotas, including: * **Reporting:** `/v3/reporting/*` * **Sequence statistics:** * `/v3/sequences/{id}/stats` * `/v3/sequences/stats` Analytics and reporting endpoints may return `429 Too Many Requests` before the general limits are reached. ## The 429 response When a rate limit is exceeded, the API returns: * **Status:** `429 Too Many Requests` * **Headers:** * `Retry-After: ` — seconds to wait before the quota window resets * `Content-Type: application/problem+json` ## Handling 429 Wait for the number of seconds specified in the `Retry-After` header before retrying the request. For bulk operations, process requests sequentially or use a small concurrency limit instead of sending many requests in parallel. # Platform overview Source: https://docs.reply.io/getting-started One platform, four access layers — API, MCP, CLI, and Skills over the same Reply.io workspace. Reply.io exposes one sales-engagement platform through four access layers. They share the same account, the same [API key](/api-reference/authentication), the same object model, and the same [rate limits](/api-reference/rate-limits) — pick the surface that fits how you (or your agent) work. ## Pick your surface The exhaustive surface. Every endpoint, schema, and webhook — for production integrations. 70 annotated tools for MCP clients — Claude, Cursor, and custom agents. `reply` in your terminal — sign in once, then call any v3 endpoint as yourself. Packaged agent workflows with confirmation gates, executed through the CLI. Not sure which to use? See [Choose your interface](/agents/choose-your-interface). ## Go further Task-based guides — from importing contacts to building an AI SDR. Agentic capabilities, safety rules, and drop-in prompts. Download the OpenAPI spec or import the Postman collection. Ask questions, share feedback, and request features. # OpenAPI & Postman Source: https://docs.reply.io/openapi-postman OpenAPI specs and Postman collections for the Reply API. ## OpenAPI The complete Reply API specification is available in OpenAPI 3.1 format. Use it to: * Generate client libraries * Explore the API structure * Import the API into tools such as Postman ## OpenAPI Spec Open the complete OpenAPI specification (YAML) ## Postman Import the Reply API collection into Postman to explore and test the API. ### What's included The collection includes: * All Reply API endpoints, including Sequences, Contacts, Email Accounts, Templates, and more * An environment template with preconfigured variables * Bearer token authentication already set up ## Setup 1. Sign in to [Reply.io account](https://run.reply.io) 2. Go to **Settings → API Key**. 3. Create a new API key or copy an existing one. 1. Open Postman. 2. Click **Import**. 3. Select **Link** and paste the collection URL. 4. Click **Import**. Create a Postman environment with the following variables: | Variable | Description | Example | | --------- | --------------------- | -------------------------------------------- | | `baseUrl` | API base URL | [https://api.reply.io](https://api.reply.io) | | `apiKey` | Your Reply.io API key | `************` | Include your API key as a Bearer token: ```text theme={null} Authorization: Bearer {{apiKey}} ``` ## Test your setup Send a request to: ```bash theme={null} GET https://api.reply.io/v3/whoami Authorization: Bearer your_api_key_here ``` If authentication succeeds, the API returns information about the authenticated user. # Slack community Source: https://docs.reply.io/slack Connect with other developers, ask questions, and share feedback. Join the Reply developer community on Slack to ask questions, share feedback, and discuss the API. No Reply account required. # Add accounts to an account list Source: https://docs.reply.io/api-reference/account-lists/add-accounts-to-an-account-list /api-reference/bundled.yaml post /v3/contact-account-lists/{id}/add-accounts _Requires the `contacts:operate` scope (or a broader one that includes it)._ Adds accounts to the specified account list, preserving any other list memberships. This is a non-atomic operation: successfully added accounts are not rolled back if some fail. The response contains only the failed items with their error details. # Upload attachment Source: https://docs.reply.io/api-reference/attachments/upload-attachment /api-reference/bundled.yaml post /v3/attachments _Requires the `other:write` scope (or a broader one that includes it)._ Uploads a single file as a `multipart/form-data` request and returns its attachment id. Use the returned `id` in `attachmentIds` arrays on email-template, sequence-step, and inbox-message endpoints to attach the file to outbound communications. # Upload voice attachment Source: https://docs.reply.io/api-reference/attachments/upload-voice-attachment /api-reference/bundled.yaml post /v3/attachments/voice Uploads an audio file as a `multipart/form-data` request, converts it to LinkedIn voice format, and returns the attachment metadata including the duration. Use the returned `id` to attach the voice message to LinkedIn voice outreach endpoints. # Cancel a background job Source: https://docs.reply.io/api-reference/background-jobs/cancel-a-background-job /api-reference/bundled.yaml post /v3/background-jobs/{jobId}/cancel _Requires the `other:operate` scope (or a broader one that includes it)._ Requests cancellation of a background job. Idempotent — cancelling an already-terminal job returns 204 without effect on the worker. The request body is optional; if provided, the `reason` is recorded alongside the cancellation event. # Get a background job Source: https://docs.reply.io/api-reference/background-jobs/get-a-background-job /api-reference/bundled.yaml get /v3/background-jobs/{jobId} _Requires the `other:read` scope (or a broader one that includes it)._ Returns the full record for a background job, including raw input (`jsonData`) and result (`jsonDataResult`) JSON payloads when available. # List background jobs Source: https://docs.reply.io/api-reference/background-jobs/list-background-jobs /api-reference/bundled.yaml get /v3/background-jobs _Requires the `other:read` scope (or a broader one that includes it)._ Returns a paginated list of background jobs created by the current user. Optionally filter by category suffix. # Bulk create domain blacklist rules Source: https://docs.reply.io/api-reference/contact-blacklist-rules/bulk-create-domain-blacklist-rules /api-reference/bundled.yaml post /v3/contact-blacklist-rules/domains/bulk _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates multiple domain blacklist rules. Non-atomic — some may succeed while others fail. Each item in the response array contains the created ID or error details. # Bulk create email blacklist rules Source: https://docs.reply.io/api-reference/contact-blacklist-rules/bulk-create-email-blacklist-rules /api-reference/bundled.yaml post /v3/contact-blacklist-rules/emails/bulk _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates multiple email blacklist rules. Non-atomic — some may succeed while others fail. Each item in the response array contains the created ID or error details. # Bulk create email exception blacklist rules Source: https://docs.reply.io/api-reference/contact-blacklist-rules/bulk-create-email-exception-blacklist-rules /api-reference/bundled.yaml post /v3/contact-blacklist-rules/email-exceptions/bulk _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates multiple email exception blacklist rules. Non-atomic — some may succeed while others fail. Each item in the response array contains the created ID or error details. # Bulk delete domain blacklist rules Source: https://docs.reply.io/api-reference/contact-blacklist-rules/bulk-delete-domain-blacklist-rules /api-reference/bundled.yaml post /v3/contact-blacklist-rules/domains/bulk-delete _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes multiple domain blacklist rules by ID. Non-atomic — some may succeed while others fail. Items not in the response dictionary succeeded. # Bulk delete email blacklist rules Source: https://docs.reply.io/api-reference/contact-blacklist-rules/bulk-delete-email-blacklist-rules /api-reference/bundled.yaml post /v3/contact-blacklist-rules/emails/bulk-delete _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes multiple email blacklist rules by ID. Non-atomic — some may succeed while others fail. Items not in the response dictionary succeeded. # Bulk delete email exception blacklist rules Source: https://docs.reply.io/api-reference/contact-blacklist-rules/bulk-delete-email-exception-blacklist-rules /api-reference/bundled.yaml post /v3/contact-blacklist-rules/email-exceptions/bulk-delete _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes multiple email exception blacklist rules by ID. Non-atomic — some may succeed while others fail. Items not in the response dictionary succeeded. # Create a domain blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/create-a-domain-blacklist-rule /api-reference/bundled.yaml post /v3/contact-blacklist-rules/domains _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates a new domain blacklist rule. # Create an email blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/create-an-email-blacklist-rule /api-reference/bundled.yaml post /v3/contact-blacklist-rules/emails _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates a new email blacklist rule. # Create an email exception blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/create-an-email-exception-blacklist-rule /api-reference/bundled.yaml post /v3/contact-blacklist-rules/email-exceptions _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates a new email exception blacklist rule. # Delete a domain blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/delete-a-domain-blacklist-rule /api-reference/bundled.yaml delete /v3/contact-blacklist-rules/domains/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes an existing domain blacklist rule. Global rules (seeded by the system) cannot be deleted. # Delete an email blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/delete-an-email-blacklist-rule /api-reference/bundled.yaml delete /v3/contact-blacklist-rules/emails/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes an existing email blacklist rule. Global rules (seeded by the system) cannot be deleted. # Delete an email exception blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/delete-an-email-exception-blacklist-rule /api-reference/bundled.yaml delete /v3/contact-blacklist-rules/email-exceptions/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes an existing email exception blacklist rule. # Get a domain blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/get-a-domain-blacklist-rule /api-reference/bundled.yaml get /v3/contact-blacklist-rules/domains/{id} _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a single domain blacklist rule by ID. # Get an email blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/get-an-email-blacklist-rule /api-reference/bundled.yaml get /v3/contact-blacklist-rules/emails/{id} _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a single email blacklist rule by ID. # Get an email exception blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/get-an-email-exception-blacklist-rule /api-reference/bundled.yaml get /v3/contact-blacklist-rules/email-exceptions/{id} _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a single email exception blacklist rule by ID. # List domain blacklist rules Source: https://docs.reply.io/api-reference/contact-blacklist-rules/list-domain-blacklist-rules /api-reference/bundled.yaml get /v3/contact-blacklist-rules/domains _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a paginated list of domain blacklist rules. # List email blacklist rules Source: https://docs.reply.io/api-reference/contact-blacklist-rules/list-email-blacklist-rules /api-reference/bundled.yaml get /v3/contact-blacklist-rules/emails _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a paginated list of email blacklist rules. # List email exception blacklist rules Source: https://docs.reply.io/api-reference/contact-blacklist-rules/list-email-exception-blacklist-rules /api-reference/bundled.yaml get /v3/contact-blacklist-rules/email-exceptions _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a paginated list of email exception blacklist rules. # Update a domain blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/update-a-domain-blacklist-rule /api-reference/bundled.yaml put /v3/contact-blacklist-rules/domains/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Updates an existing domain blacklist rule. # Update an email blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/update-an-email-blacklist-rule /api-reference/bundled.yaml put /v3/contact-blacklist-rules/emails/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Updates an existing email blacklist rule. # Update an email exception blacklist rule Source: https://docs.reply.io/api-reference/contact-blacklist-rules/update-an-email-exception-blacklist-rule /api-reference/bundled.yaml put /v3/contact-blacklist-rules/email-exceptions/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Updates an existing email exception blacklist rule. # Enrich contacts by email Source: https://docs.reply.io/api-reference/contact-enrichment/enrich-contacts-by-email /api-reference/bundled.yaml post /v3/contacts/enrich-by-email **Coming soon.** This endpoint will be available by late August 2026. Enriches contact data using each contact's existing email address. Consumes credits from the Reply credit pool — 1 credit per contact. # Enrich contacts by LinkedIn URL Source: https://docs.reply.io/api-reference/contact-enrichment/enrich-contacts-by-linkedin-url /api-reference/bundled.yaml post /v3/contacts/enrich-by-linkedin **Coming soon.** This endpoint will be available by late August 2026. Enriches contact data using each contact's LinkedIn URL. Optionally also finds email and/or phone in the same call. Consumes credits from the Reply credit pool: 1 per contact, plus (when find-email is enabled) 2 and (when find-phone is enabled) 3 per contact. # Fill AI custom fields Source: https://docs.reply.io/api-reference/contact-enrichment/fill-ai-custom-fields /api-reference/bundled.yaml post /v3/contacts/enrich-ai-custom-fields **Coming soon.** This endpoint will be available by late August 2026. Fills configured AI custom field values for contacts using AI. Consumes credits from the Reply credit pool — 1 credit per contact-field combination. # Find missing email addresses Source: https://docs.reply.io/api-reference/contact-enrichment/find-missing-email-addresses /api-reference/bundled.yaml post /v3/contacts/find-emails **Coming soon.** This endpoint will be available by late August 2026. Finds missing email addresses for contacts that currently don't have one. Consumes credits from the Reply credit pool — 2 credits per contact. # Find phone numbers Source: https://docs.reply.io/api-reference/contact-enrichment/find-phone-numbers /api-reference/bundled.yaml post /v3/contacts/find-phones **Coming soon.** This endpoint will be available by late August 2026. Finds phone numbers for contacts. Consumes credits from the Reply credit pool — 3 credits per contact. # Add contacts to a contact list Source: https://docs.reply.io/api-reference/contact-lists/add-contacts-to-a-contact-list /api-reference/bundled.yaml post /v3/contact-lists/{id}/add-contacts _Requires the `contacts:operate` scope (or a broader one that includes it)._ Adds contacts to the specified contact list. This is a non-atomic operation: successfully added contacts are not rolled back if some fail. The response contains only the failed items with their error details. # Create a contact list Source: https://docs.reply.io/api-reference/contact-lists/create-a-contact-list /api-reference/bundled.yaml post /v3/contact-lists _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates a new contact list. # Delete a contact list Source: https://docs.reply.io/api-reference/contact-lists/delete-a-contact-list /api-reference/bundled.yaml delete /v3/contact-lists/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes an existing contact list. # Get a contact list Source: https://docs.reply.io/api-reference/contact-lists/get-a-contact-list /api-reference/bundled.yaml get /v3/contact-lists/{id} _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a single contact list by ID. # Get contact's lists Source: https://docs.reply.io/api-reference/contact-lists/get-contacts-lists /api-reference/bundled.yaml get /v3/contacts/{id}/lists _Requires the `contacts:read` scope (or a broader one that includes it)._ Use this endpoint when you need to see which contact lists a contact belongs to, including each list's name and whether it is shared with your team. # List contact lists Source: https://docs.reply.io/api-reference/contact-lists/list-contact-lists /api-reference/bundled.yaml get /v3/contact-lists _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a paginated list of all contact lists. # Move contacts to a contact list Source: https://docs.reply.io/api-reference/contact-lists/move-contacts-to-a-contact-list /api-reference/bundled.yaml post /v3/contact-lists/{id}/move-contacts _Requires the `contacts:operate` scope (or a broader one that includes it)._ Moves contacts to the specified contact list. This is a non-atomic operation: successfully moved contacts are not rolled back if some fail. The response contains only the failed items with their error details. # Share a contact list Source: https://docs.reply.io/api-reference/contact-lists/share-a-contact-list /api-reference/bundled.yaml post /v3/contact-lists/{id}/share _Requires the `contacts:write` scope (or a broader one that includes it)._ Makes a contact list shared across the team. # Unshare a contact list Source: https://docs.reply.io/api-reference/contact-lists/unshare-a-contact-list /api-reference/bundled.yaml post /v3/contact-lists/{id}/unshare _Requires the `contacts:write` scope (or a broader one that includes it)._ Makes a shared contact list private again. # Update a contact list Source: https://docs.reply.io/api-reference/contact-lists/update-a-contact-list /api-reference/bundled.yaml put /v3/contact-lists/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Updates an existing contact list name. # Add a note to a contact Source: https://docs.reply.io/api-reference/contacts/add-a-note-to-a-contact /api-reference/bundled.yaml post /v3/contacts/{id}/notes _Requires the `contacts:operate` scope (or a broader one that includes it)._ Adds a note to an existing contact # Bulk delete contacts Source: https://docs.reply.io/api-reference/contacts/bulk-delete-contacts /api-reference/bundled.yaml post /v3/contacts/bulk-delete _Requires the `contacts:write` scope (or a broader one that includes it)._ Use this endpoint when you need to remove several contacts in a single call. Contacts are processed independently: the response maps each contact id that could not be deleted to the reason it was skipped. # Change contacts owner Source: https://docs.reply.io/api-reference/contacts/change-contacts-owner /api-reference/bundled.yaml put /v3/contacts/owner _Requires the `contacts:operate` scope (or a broader one that includes it)._ Changes the owner of one or more contacts to a different team member # Count filtered contacts Source: https://docs.reply.io/api-reference/contacts/count-filtered-contacts /api-reference/bundled.yaml post /v3/contacts/filter/count **Coming soon.** This endpoint will be available by late August 2026. _Requires the `contacts:read` scope (or a broader one that includes it)._ Use this endpoint when you need only the number of contacts that match a set of filter criteria — for example to show a total or decide whether to page through the results — without fetching the contacts themselves. It accepts the same request body as the filter endpoint. # Create a contact Source: https://docs.reply.io/api-reference/contacts/create-a-contact /api-reference/bundled.yaml post /v3/contacts _Requires the `contacts:write` scope (or a broader one that includes it)._ Use this endpoint when you need to add a single new contact to your account — for example when capturing a lead from your own application. Provide any known profile fields and custom field values; the contact is created under your ownership and returned with its assigned id. To add many contacts at once, or to update existing ones by a match key, use the import endpoint instead. # Delete a contact Source: https://docs.reply.io/api-reference/contacts/delete-a-contact /api-reference/bundled.yaml delete /v3/contacts/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Use this endpoint when you need to remove a single contact from your account by its id. To remove several contacts in one call, use the bulk-delete endpoint instead. # Filter contacts Source: https://docs.reply.io/api-reference/contacts/filter-contacts /api-reference/bundled.yaml post /v3/contacts/filter _Requires the `contacts:read` scope (or a broader one that includes it)._ Use this endpoint when you need a filtered, sorted page of contacts that a plain email or LinkedIn lookup cannot express. Combine field rules (property, condition, value) with optional scoping by list, sequence, or sequence step, a free-text search term, and a sort order. Results are paged with the top and skip query parameters. To get only the total for the same criteria, use filter/count. # Get a contact Source: https://docs.reply.io/api-reference/contacts/get-a-contact /api-reference/bundled.yaml get /v3/contacts/{id} _Requires the `contacts:read` scope (or a broader one that includes it)._ Use this endpoint when you need the full record of a single contact, identified by its Reply contact id — including profile fields, owner, opt-out, call and meeting status, and all custom field values. # Get a contact's statuses Source: https://docs.reply.io/api-reference/contacts/get-a-contacts-statuses /api-reference/bundled.yaml get /v3/contacts/{id}/statuses _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns the contact's current global flags (`isOptedOut`, `callStatus`, `meetingStatus`) plus per-sequence status (`statusInSequence`) and email disposition (`isReplied`, `isBounced`) for each sequence the contact is enrolled in. # Get activities for a contact Source: https://docs.reply.io/api-reference/contacts/get-activities-for-a-contact /api-reference/bundled.yaml get /v3/contacts/{id}/activities _Requires the `contacts:read` scope (or a broader one that includes it)._ Use this endpoint when you need a contact's activity history — the emails, calls, status changes, and other tracked events recorded on its timeline. Results are paged with the top and skip query parameters. # Get inbox threads for a contact Source: https://docs.reply.io/api-reference/contacts/get-inbox-threads-for-a-contact /api-reference/bundled.yaml get /v3/contacts/{id}/inbox-threads **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:read` scope (or a broader one that includes it)._ Use this endpoint when you need the email conversation threads exchanged with a contact, grouped as they appear in your inbox. Results are paged with the top and skip query parameters. # Get sequences for a contact Source: https://docs.reply.io/api-reference/contacts/get-sequences-for-a-contact /api-reference/bundled.yaml get /v3/contacts/{id}/sequences _Requires the `contacts:read` scope (or a broader one that includes it)._ Use this endpoint when you need to see which sequences a contact is enrolled in, together with each sequence's name, the contact's status in it, the current step, and when they were added. # Import contacts Source: https://docs.reply.io/api-reference/contacts/import-contacts /api-reference/bundled.yaml post /v3/contacts/import _Requires the `contacts:write` scope (or a broader one that includes it)._ Use this endpoint when you need to add or update many contacts in one call — for example when syncing contacts from another system. Each item uses the same fields as the contact update model. Use options to control deduplication, list assignment, and other import behavior: which keys identify an existing contact (email plus any of LinkedIn URL, phone, name, company, or custom fields), whether matched contacts are overwritten or skipped, whether previously deleted contacts are restored, and which lists or sequence the imported contacts are added to. The response reports how many contacts were added, updated, skipped, or failed, with a per-item outcome. # List all contacts Source: https://docs.reply.io/api-reference/contacts/list-all-contacts /api-reference/bundled.yaml get /v3/contacts _Requires the `contacts:read` scope (or a broader one that includes it)._ Use this endpoint when you need to browse your contacts or look one up by its email or LinkedIn URL. Results are returned as a page controlled by the top and skip query parameters; omit both to get the first page. Pass email and/or linkedIn to narrow the results to contacts matching those exact identifiers. For richer, rule-based filtering use the filter endpoint instead. # Mark or unmark contacts as bounced Source: https://docs.reply.io/api-reference/contacts/mark-or-unmark-contacts-as-bounced /api-reference/bundled.yaml post /v3/contacts/set-bounced _Requires the `contacts:operate` scope (or a broader one that includes it)._ Marks the given contacts as bounced (`isBounced: true`) or clears the bounced flag (`isBounced: false`) across **every sequence** they are currently enrolled in. When clearing the flag (`isBounced: false`), `resendEmails` is required: pass `true` to retry the previously bounced step or `false` to leave the schedule untouched. When marking as bounced (`isBounced: true`), `resendEmails` must be omitted. To restrict the change to a single sequence, use `POST /v3/sequences/{id}/contacts/set-bounced` instead. # Mark or unmark contacts as replied Source: https://docs.reply.io/api-reference/contacts/mark-or-unmark-contacts-as-replied /api-reference/bundled.yaml post /v3/contacts/set-replied _Requires the `contacts:operate` scope (or a broader one that includes it)._ Marks the given contacts as replied (`isReplied: true`) or clears the replied flag (`isReplied: false`) across **every sequence** they are currently enrolled in. To restrict the change to a single sequence, use `POST /v3/sequences/{id}/contacts/set-replied` instead. # Move a contact to a sequence Source: https://docs.reply.io/api-reference/contacts/move-a-contact-to-a-sequence /api-reference/bundled.yaml post /v3/contacts/{id}/move-to-sequence _Requires the `contacts:operate` scope (or a broader one that includes it)._ Moves a contact to a different sequence, optionally removing from existing sequences # Set contacts' in-sequence status Source: https://docs.reply.io/api-reference/contacts/set-contacts-in-sequence-status /api-reference/bundled.yaml post /v3/contacts/set-status-in-sequence _Requires the `contacts:operate` scope (or a broader one that includes it)._ Sets the in-sequence status (`active` / `paused` / `finished` / `outOfOffice`) for the given contacts across **every sequence** they are currently enrolled in. Replied and Bounced are **not** values of this enum — use `POST /v3/contacts/set-replied` or `POST /v3/contacts/set-bounced` for those. To restrict the change to a single sequence, use `POST /v3/sequences/{id}/contacts/set-status-in-sequence` instead. `paused` requires the contact to currently be `active` in the sequence — pausing from any other state is reported per-item as `invalidStatusTransition`. The other targets (`active`, `finished`, `outOfOffice`) accept any current state. # Update a contact Source: https://docs.reply.io/api-reference/contacts/update-a-contact /api-reference/bundled.yaml patch /v3/contacts/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Use this endpoint when you need to change specific fields on an existing contact without resending the whole record. Only the properties present in the request body are updated; omitted properties are left unchanged, while sending an explicit null clears a nullable field. Use it to correct profile data, reassign ownership, or set opt-out, call, and meeting status. # Create a custom field Source: https://docs.reply.io/api-reference/custom-fields/create-a-custom-field /api-reference/bundled.yaml post /v3/custom-fields _Requires the `contacts:write` scope (or a broader one that includes it)._ Creates a new custom field # Delete a custom field Source: https://docs.reply.io/api-reference/custom-fields/delete-a-custom-field /api-reference/bundled.yaml delete /v3/custom-fields/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Deletes an existing custom field # Get a custom field Source: https://docs.reply.io/api-reference/custom-fields/get-a-custom-field /api-reference/bundled.yaml get /v3/custom-fields/{id} _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a single custom field by ID # List all custom fields Source: https://docs.reply.io/api-reference/custom-fields/list-all-custom-fields /api-reference/bundled.yaml get /v3/custom-fields _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a list of all custom fields in your account # Update a custom field Source: https://docs.reply.io/api-reference/custom-fields/update-a-custom-field /api-reference/bundled.yaml put /v3/custom-fields/{id} _Requires the `contacts:write` scope (or a broader one that includes it)._ Updates an existing custom field # Send a direct email to a contact Source: https://docs.reply.io/api-reference/direct-outreach/send-a-direct-email-to-a-contact /api-reference/bundled.yaml post /v3/contacts/{id}/send-direct-email _Requires the `contacts:operate` scope (or a broader one that includes it)._ Sends a one-off email directly to a contact outside of any sequence # Send a LinkedIn connection request to a contact Source: https://docs.reply.io/api-reference/direct-outreach/send-a-linkedin-connection-request-to-a-contact /api-reference/bundled.yaml post /v3/contacts/{id}/send-direct-linkedin-connect _Requires the `contacts:operate` scope (or a broader one that includes it)._ Sends a direct LinkedIn connection request to the contact outside of any sequence. The contact must have a LinkedIn profile URL set. The caller must own an active LinkedIn account (`linkedInAccountId`). # Send a LinkedIn InMail to a contact Source: https://docs.reply.io/api-reference/direct-outreach/send-a-linkedin-inmail-to-a-contact /api-reference/bundled.yaml post /v3/contacts/{id}/send-direct-linkedin-inmail _Requires the `contacts:operate` scope (or a broader one that includes it)._ Sends a direct LinkedIn InMail message to the contact outside of any sequence. Requires a Sales Navigator account with available InMail credits. # Send a LinkedIn message to a contact Source: https://docs.reply.io/api-reference/direct-outreach/send-a-linkedin-message-to-a-contact /api-reference/bundled.yaml post /v3/contacts/{id}/send-direct-linkedin-message _Requires the `contacts:operate` scope (or a broader one that includes it)._ Sends a direct LinkedIn message to the contact outside of any sequence. The caller must already be connected with the contact on LinkedIn. # Send a LinkedIn voice message to a contact Source: https://docs.reply.io/api-reference/direct-outreach/send-a-linkedin-voice-message-to-a-contact /api-reference/bundled.yaml post /v3/contacts/{id}/send-direct-linkedin-voice _Requires the `contacts:operate` scope (or a broader one that includes it)._ Sends a pre-recorded voice message to the contact via LinkedIn outside of any sequence. The caller must already be connected with the contact on LinkedIn. Upload audio files via `POST /v3/attachments/voice` to obtain a `voiceAttachmentId`. # Send an AI-generated LinkedIn voice message to a contact Source: https://docs.reply.io/api-reference/direct-outreach/send-an-ai-generated-linkedin-voice-message-to-a-contact /api-reference/bundled.yaml post /v3/contacts/{id}/send-direct-linkedin-ai-voice _Requires the `contacts:operate` scope (or a broader one that includes it)._ Generates and sends an AI voice message to the contact via LinkedIn outside of any sequence. The caller must already be connected with the contact on LinkedIn. The voice is synthesized from the provided script using the account's text-to-speech settings. # Add tags to an email account Source: https://docs.reply.io/api-reference/email-accounts/add-tags-to-an-email-account /api-reference/bundled.yaml post /v3/email-accounts/{id}/tags _Requires the `channels:operate` scope (or a broader one that includes it)._ Adds one or more tags to an email account by tag name. Tags that don't exist yet will be created automatically. # Bulk delete email accounts Source: https://docs.reply.io/api-reference/email-accounts/bulk-delete-email-accounts /api-reference/bundled.yaml post /v3/email-accounts/bulk-delete _Requires the `channels:write` scope (or a broader one that includes it)._ Deletes multiple email accounts at once. This is a non-atomic operation: successfully deleted accounts are not rolled back if some fail. The response contains only the failed items with their error details. # Connect Gmail account via OAuth Source: https://docs.reply.io/api-reference/email-accounts/connect-gmail-account-via-oauth /api-reference/bundled.yaml get /v3/email-accounts/connect/gmail _Requires the `channels:write` scope (or a broader one that includes it)._ Initiates Gmail OAuth flow. Returns a 302 redirect to Google's OAuth consent page. After authorization, the email account will be automatically connected. # Connect Office 365 account via OAuth Source: https://docs.reply.io/api-reference/email-accounts/connect-office-365-account-via-oauth /api-reference/bundled.yaml get /v3/email-accounts/connect/office-365 _Requires the `channels:write` scope (or a broader one that includes it)._ Initiates Microsoft Office 365 OAuth flow. Returns a 302 redirect to Microsoft's OAuth consent page. After authorization, the email account will be automatically connected. # Create an email account Source: https://docs.reply.io/api-reference/email-accounts/create-an-email-account /api-reference/bundled.yaml post /v3/email-accounts _Requires the `channels:write` scope (or a broader one that includes it)._ Creates a new email account. Only works with custom email account providers (SMTP/IMAP). # Delete an email account Source: https://docs.reply.io/api-reference/email-accounts/delete-an-email-account /api-reference/bundled.yaml delete /v3/email-accounts/{id} _Requires the `channels:write` scope (or a broader one that includes it)._ Deletes an existing email account by ID. # Filter email account stats Source: https://docs.reply.io/api-reference/email-accounts/filter-email-account-stats /api-reference/bundled.yaml post /v3/email-accounts/stats **Coming soon.** This endpoint will be available by late August 2026. _Requires the `channels:read` scope (or a broader one that includes it)._ Returns a paginated list of email account sending statistics matching the provided filter criteria. # Filter email accounts Source: https://docs.reply.io/api-reference/email-accounts/filter-email-accounts /api-reference/bundled.yaml post /v3/email-accounts/filter _Requires the `channels:read` scope (or a broader one that includes it)._ Returns a paginated list of email accounts matching the provided filter criteria. In Public or Organization mode, results include all team members' accounts. Use `ownerUserIds` filter to restrict by specific users. When no accounts match the filter, the response contains an empty `items` array with `hasMore: false` — this is normal behavior, not an error. # Get an email account Source: https://docs.reply.io/api-reference/email-accounts/get-an-email-account /api-reference/bundled.yaml get /v3/email-accounts/{id} _Requires the `channels:read` scope (or a broader one that includes it)._ Returns the full details of a single email account including all configuration sections. # Get email account stats Source: https://docs.reply.io/api-reference/email-accounts/get-email-account-stats /api-reference/bundled.yaml get /v3/email-accounts/{id}/stats **Coming soon.** This endpoint will be available by late August 2026. _Requires the `channels:read` scope (or a broader one that includes it)._ Returns sending statistics for a single email account. # List email account tags Source: https://docs.reply.io/api-reference/email-accounts/list-email-account-tags /api-reference/bundled.yaml get /v3/email-accounts/tags _Requires the `channels:read` scope (or a broader one that includes it)._ Returns all email account tags available to the authenticated user. # List email accounts Source: https://docs.reply.io/api-reference/email-accounts/list-email-accounts /api-reference/bundled.yaml get /v3/email-accounts _Requires the `channels:read` scope (or a broader one that includes it)._ Returns a paginated list of email accounts. By default returns all email accounts visible to the authenticated user, including team members' accounts in Public or Organization mode. Use `my=true` to restrict results to only the authenticated user's own accounts. # Remove tags from an email account Source: https://docs.reply.io/api-reference/email-accounts/remove-tags-from-an-email-account /api-reference/bundled.yaml delete /v3/email-accounts/{id}/tags _Requires the `channels:operate` scope (or a broader one that includes it)._ Removes one or more tags from an email account by tag name. # Resume sending Source: https://docs.reply.io/api-reference/email-accounts/resume-sending /api-reference/bundled.yaml post /v3/email-accounts/{id}/resume-sending _Requires the `channels:operate` scope (or a broader one that includes it)._ Resumes email sending for an account that was paused or throttled by the provider. # Set default email account Source: https://docs.reply.io/api-reference/email-accounts/set-default-email-account /api-reference/bundled.yaml post /v3/email-accounts/{id}/set-default _Requires the `channels:operate` scope (or a broader one that includes it)._ Sets the specified email account as the default for the authenticated user. # Test IMAP connectivity Source: https://docs.reply.io/api-reference/email-accounts/test-imap-connectivity /api-reference/bundled.yaml post /v3/email-accounts/test/imap _Requires the `channels:operate` scope (or a broader one that includes it)._ Tests connectivity to an IMAP server with the provided credentials without creating an email account. # Test SMTP connectivity Source: https://docs.reply.io/api-reference/email-accounts/test-smtp-connectivity /api-reference/bundled.yaml post /v3/email-accounts/test/smtp _Requires the `channels:operate` scope (or a broader one that includes it)._ Tests connectivity to an SMTP server with the provided credentials without creating an email account. # Update a tag Source: https://docs.reply.io/api-reference/email-accounts/update-a-tag /api-reference/bundled.yaml put /v3/email-accounts/tags/{tagId} _Requires the `channels:operate` scope (or a broader one that includes it)._ Updates the name and/or color of an email account tag. # Update an email account Source: https://docs.reply.io/api-reference/email-accounts/update-an-email-account /api-reference/bundled.yaml patch /v3/email-accounts/{id} _Requires the `channels:write` scope (or a broader one that includes it)._ Partially updates an email account. Only works with custom email account providers (SMTP/IMAP). Provide only the sections and fields you want to change; omitted fields are left unchanged. # Clone an email template Source: https://docs.reply.io/api-reference/email-templates/clone-an-email-template /api-reference/bundled.yaml post /v3/email-templates/{id}/clone _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a copy of an existing email template. # Create an email template Source: https://docs.reply.io/api-reference/email-templates/create-an-email-template /api-reference/bundled.yaml post /v3/email-templates _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new email template. # Delete an email template Source: https://docs.reply.io/api-reference/email-templates/delete-an-email-template /api-reference/bundled.yaml delete /v3/email-templates/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes an email template by ID. # Get an email template Source: https://docs.reply.io/api-reference/email-templates/get-an-email-template /api-reference/bundled.yaml get /v3/email-templates/{id} _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a single email template by ID. # List email templates Source: https://docs.reply.io/api-reference/email-templates/list-email-templates /api-reference/bundled.yaml get /v3/email-templates _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a paginated list of email templates for the authenticated user. # Move an email template Source: https://docs.reply.io/api-reference/email-templates/move-an-email-template /api-reference/bundled.yaml post /v3/email-templates/{id}/move _Requires the `sequences:write` scope (or a broader one that includes it)._ Moves an email template to a different folder. # Render an email template Source: https://docs.reply.io/api-reference/email-templates/render-an-email-template /api-reference/bundled.yaml post /v3/email-templates/{id}/render _Requires the `sequences:operate` scope (or a broader one that includes it)._ Renders an email template by substituting variables with actual contact data. # Send a test email Source: https://docs.reply.io/api-reference/email-templates/send-a-test-email /api-reference/bundled.yaml post /v3/email-templates/{id}/send-test _Requires the `sequences:operate` scope (or a broader one that includes it)._ Sends a test email using the specified template. # Update an email template Source: https://docs.reply.io/api-reference/email-templates/update-an-email-template /api-reference/bundled.yaml put /v3/email-templates/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Updates an existing email template. # Create an email template folder Source: https://docs.reply.io/api-reference/email-templates/create-an-email-template-folder /api-reference/bundled.yaml post /v3/email-template-folders _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new email template folder. # Delete an email template folder Source: https://docs.reply.io/api-reference/email-templates/delete-an-email-template-folder /api-reference/bundled.yaml delete /v3/email-template-folders/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes an email template folder by ID. # Get an email template folder Source: https://docs.reply.io/api-reference/email-templates/get-an-email-template-folder /api-reference/bundled.yaml get /v3/email-template-folders/{id} _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a single email template folder by ID. # Get template variables Source: https://docs.reply.io/api-reference/email-templates/get-template-variables /api-reference/bundled.yaml get /v3/email-templates/variables _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns all available template variables grouped by category (prospect, team, advanced). # List email template folders Source: https://docs.reply.io/api-reference/email-templates/list-email-template-folders /api-reference/bundled.yaml get /v3/email-template-folders _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns all email template folders for the authenticated user. # Share an email template folder Source: https://docs.reply.io/api-reference/email-templates/share-an-email-template-folder /api-reference/bundled.yaml post /v3/email-template-folders/{id}/share _Requires the `sequences:write` scope (or a broader one that includes it)._ Shares a personal email template folder with the team. # Update an email template folder Source: https://docs.reply.io/api-reference/email-templates/update-an-email-template-folder /api-reference/bundled.yaml put /v3/email-template-folders/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Updates an existing email template folder. # Upload a template attachment Source: https://docs.reply.io/api-reference/email-templates/upload-a-template-attachment /api-reference/bundled.yaml post /v3/email-template-attachments Uploads a file to be used as an email template attachment. Returns the attachment metadata including the ID to use when creating or updating templates. # Estimate email validation Source: https://docs.reply.io/api-reference/email-validations/estimate-email-validation /api-reference/bundled.yaml post /v3/email-validations/estimate _Requires the `contacts:read` scope (or a broader one that includes it)._ Synchronous probe — given a list of contact IDs, returns counts, credit sufficiency, and any blockers that would prevent scheduling. Useful for showing pre-flight feedback in the UI before triggering `/schedule`. # Schedule email validation Source: https://docs.reply.io/api-reference/email-validations/schedule-email-validation /api-reference/bundled.yaml post /v3/email-validations/schedule _Requires the `contacts:operate` scope (or a broader one that includes it)._ Schedules an asynchronous email-validation job for the supplied contact IDs. Returns `202 Accepted` with a `Location` header pointing at `/v3/background-jobs/{jobId}` — poll that endpoint for status and the eventual result. The eligibility filter (team scope + `RequiresValidation` status) and the credits cap applied here mirror the `/estimate` semantics. Set `acceptPartial = true` to schedule whatever credits allow when the team's balance is below the eligible count. # Create a holiday calendar Source: https://docs.reply.io/api-reference/holiday-calendars/create-a-holiday-calendar /api-reference/bundled.yaml post /v3/holiday-calendars _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new custom holiday calendar. # Delete a holiday calendar Source: https://docs.reply.io/api-reference/holiday-calendars/delete-a-holiday-calendar /api-reference/bundled.yaml delete /v3/holiday-calendars/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes a custom holiday calendar. Only custom calendars can be deleted. # Export a holiday calendar as CSV Source: https://docs.reply.io/api-reference/holiday-calendars/export-a-holiday-calendar-as-csv /api-reference/bundled.yaml get /v3/holiday-calendars/{id}/export-csv **Coming soon.** This endpoint will be available by early August 2026. _Requires the `sequences:read` scope (or a broader one that includes it)._ Exports the holidays of a calendar as a CSV file. The response filename matches the calendar name. # Get a holiday calendar Source: https://docs.reply.io/api-reference/holiday-calendars/get-a-holiday-calendar /api-reference/bundled.yaml get /v3/holiday-calendars/{id} _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a single holiday calendar by ID, including its holidays. # List holiday calendars Source: https://docs.reply.io/api-reference/holiday-calendars/list-holiday-calendars /api-reference/bundled.yaml get /v3/holiday-calendars _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns all holiday calendars available to the authenticated user, including predefined and custom calendars. # Update a holiday calendar Source: https://docs.reply.io/api-reference/holiday-calendars/update-a-holiday-calendar /api-reference/bundled.yaml put /v3/holiday-calendars/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Updates an existing custom holiday calendar. Only custom calendars can be updated. # Assign or clear a thread's category Source: https://docs.reply.io/api-reference/inbox/assign-or-clear-a-threads-category /api-reference/bundled.yaml put /v3/inbox/threads/{id}/category _Requires the `inbox:operate` scope (or a broader one that includes it)._ Sets the thread's category, or clears it when `categoryId` is `null`. Idempotent. # Assign threads to a category Source: https://docs.reply.io/api-reference/inbox/assign-threads-to-a-category /api-reference/bundled.yaml post /v3/inbox/threads/categories/{id}/thread-links/bulk _Requires the `inbox:operate` scope (or a broader one that includes it)._ Non-atomic bulk assignment — links each supplied thread to this category. Per-item failures are returned in a dictionary keyed by thread id. **Per-item error codes** | Error code | Meaning | | --- | --- | | `notFound` | Thread or category not found | | `invalidInput` | Invalid input | | `forbidden` | User not allowed to assign this thread | # Bulk-delete inbox threads Source: https://docs.reply.io/api-reference/inbox/bulk-delete-inbox-threads /api-reference/bundled.yaml post /v3/inbox/threads/bulk-delete _Requires the `inbox:operate` scope (or a broader one that includes it)._ Non-atomic bulk delete. Successful threads are removed; per-item failures (e.g. not found, forbidden) are returned in a dictionary keyed by thread id. **Per-item error codes** | Error code | Meaning | | --- | --- | | `notFound` | Thread not found | | `forbidden` | User not allowed to delete this thread | # Create inbox category Source: https://docs.reply.io/api-reference/inbox/create-inbox-category /api-reference/bundled.yaml post /v3/inbox/threads/categories _Requires the `inbox:write` scope (or a broader one that includes it)._ Creates a custom inbox category. Names must be unique within the team (case-insensitive). # Delete inbox category Source: https://docs.reply.io/api-reference/inbox/delete-inbox-category /api-reference/bundled.yaml delete /v3/inbox/threads/categories/{id} _Requires the `inbox:write` scope (or a broader one that includes it)._ Deletes a custom category and unlinks it from any threads. Reserved (system) categories reject this operation with 403 / `code: inboxCategory.cannotModifyDefault`. # Delete inbox thread Source: https://docs.reply.io/api-reference/inbox/delete-inbox-thread /api-reference/bundled.yaml delete /v3/inbox/threads/{id} _Requires the `inbox:operate` scope (or a broader one that includes it)._ Permanently deletes a single thread. # Filter inbox threads Source: https://docs.reply.io/api-reference/inbox/filter-inbox-threads /api-reference/bundled.yaml post /v3/inbox/threads/filter _Requires the `inbox:read` scope (or a broader one that includes it)._ Returns a paginated page of inbox threads matching the supplied filter. All filter fields are optional — the empty body matches the same set as `GET /v3/inbox/threads`. # Generate an AI draft reply Source: https://docs.reply.io/api-reference/inbox/generate-an-ai-draft-reply /api-reference/bundled.yaml post /v3/inbox/threads/{id}/ai-draft/generate **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. Generates an AI-suggested reply for an inbox thread. The same endpoint backs both the initial generate and the "Regenerate" action in the message editor — each call produces a fresh draft. To send the draft (with or without edits), use the existing `POST /v3/inbox/threads/{id}/messages` endpoint. # Get inbox category Source: https://docs.reply.io/api-reference/inbox/get-inbox-category /api-reference/bundled.yaml get /v3/inbox/threads/categories/{id} _Requires the `inbox:read` scope (or a broader one that includes it)._ Returns a single inbox category by id, including reserved system categories. # Get inbox thread Source: https://docs.reply.io/api-reference/inbox/get-inbox-thread /api-reference/bundled.yaml get /v3/inbox/threads/{id} _Requires the `inbox:read` scope (or a broader one that includes it)._ Returns a single thread including the ordered message history. # List inbox categories Source: https://docs.reply.io/api-reference/inbox/list-inbox-categories /api-reference/bundled.yaml get /v3/inbox/threads/categories _Requires the `inbox:read` scope (or a broader one that includes it)._ Returns all inbox categories visible to the current user, including reserved system categories. # List inbox threads Source: https://docs.reply.io/api-reference/inbox/list-inbox-threads /api-reference/bundled.yaml get /v3/inbox/threads _Requires the `inbox:read` scope (or a broader one that includes it)._ Returns a paginated page of inbox threads visible to the current user, ordered by `lastActivityDate` descending. # List messages in an inbox thread Source: https://docs.reply.io/api-reference/inbox/list-messages-in-an-inbox-thread /api-reference/bundled.yaml get /v3/inbox/threads/{id}/messages _Requires the `inbox:read` scope (or a broader one that includes it)._ Returns a paginated page of messages on the given thread, ordered by `date` ascending. Messages are polymorphic: `channel: email` carries recipient and subject metadata, `channel: linkedIn` carries only the shared base fields. # Mark threads as read Source: https://docs.reply.io/api-reference/inbox/mark-threads-as-read /api-reference/bundled.yaml post /v3/inbox/threads/mark-as-read _Requires the `inbox:operate` scope (or a broader one that includes it)._ Non-atomic bulk update — flips `isRead` to `true` on each supplied thread. Per-item failures are returned in a dictionary keyed by thread id. **Per-item error codes** | Error code | Meaning | | --- | --- | | `notFound` | Thread not found | | `forbidden` | User not allowed to access this thread | # Mark threads as unread Source: https://docs.reply.io/api-reference/inbox/mark-threads-as-unread /api-reference/bundled.yaml post /v3/inbox/threads/mark-as-unread _Requires the `inbox:operate` scope (or a broader one that includes it)._ Non-atomic bulk update — flips `isRead` to `false` on each supplied thread. Per-item failures are returned in a dictionary keyed by thread id. **Per-item error codes** | Error code | Meaning | | --- | --- | | `notFound` | Thread not found | | `forbidden` | User not allowed to access this thread | # Send a reply within a thread Source: https://docs.reply.io/api-reference/inbox/send-a-reply-within-a-thread /api-reference/bundled.yaml post /v3/inbox/threads/{id}/messages _Requires the `inbox:operate` scope (or a broader one that includes it)._ Sends an outbound message on the supplied thread. The request body''s `channel` discriminator must match the thread''s channel; mismatches are rejected with `code: inboxThread.channelMismatch`. # Submit feedback on a generated AI draft Source: https://docs.reply.io/api-reference/inbox/submit-feedback-on-a-generated-ai-draft /api-reference/bundled.yaml post /v3/inbox/threads/{id}/ai-draft/feedback **Coming soon.** This endpoint will be available by late August 2026. Records a thumbs-up / thumbs-down on the AI-generated draft, with optional dislike reasons and a freeform comment. Used as a training signal. Requires the AI SDR feature on the caller's team. # Toggle thread meeting-intent Source: https://docs.reply.io/api-reference/inbox/toggle-thread-meeting-intent /api-reference/bundled.yaml put /v3/inbox/threads/{id}/meeting-intent _Requires the `inbox:operate` scope (or a broader one that includes it)._ Sets or clears the meeting-intent flag on a thread. # Unassign threads from a category Source: https://docs.reply.io/api-reference/inbox/unassign-threads-from-a-category /api-reference/bundled.yaml post /v3/inbox/threads/categories/{id}/thread-links/bulk-delete _Requires the `inbox:operate` scope (or a broader one that includes it)._ Non-atomic bulk unassignment — clears the category link from each supplied thread when it points at this category. Per-item failures are returned in a dictionary keyed by thread id. **Per-item error codes** | Error code | Meaning | | --- | --- | | `notFound` | Thread or category not found | | `invalidInput` | Invalid input | | `forbidden` | User not allowed to modify this thread | # Update inbox category Source: https://docs.reply.io/api-reference/inbox/update-inbox-category /api-reference/bundled.yaml put /v3/inbox/threads/categories/{id} _Requires the `inbox:write` scope (or a broader one that includes it)._ Full replacement of `name` and `color` for a category. Reserved (system) categories reject this operation with 403 / `code: inboxCategory.cannotModifyDefault`. # Bulk delete LinkedIn accounts Source: https://docs.reply.io/api-reference/linkedin-accounts/bulk-delete-linkedin-accounts /api-reference/bundled.yaml post /v3/linkedin-accounts/bulk-delete _Requires the `channels:write` scope (or a broader one that includes it)._ Deletes multiple LinkedIn accounts. Returns a dictionary of failed items keyed by account ID. # Create a connection link Source: https://docs.reply.io/api-reference/linkedin-accounts/create-a-connection-link /api-reference/bundled.yaml post /v3/linkedin-accounts/connection-link _Requires the `channels:write` scope (or a broader one that includes it)._ Creates a new connection link for connecting a LinkedIn account via browser extension. Also creates a pending account entry. # Create a direct connection link Source: https://docs.reply.io/api-reference/linkedin-accounts/create-a-direct-connection-link /api-reference/bundled.yaml post /v3/linkedin-accounts/connect _Requires the `channels:write` scope (or a broader one that includes it)._ Creates a direct connection link for connecting a LinkedIn account without specifying a name upfront. # Delete a LinkedIn account Source: https://docs.reply.io/api-reference/linkedin-accounts/delete-a-linkedin-account /api-reference/bundled.yaml delete /v3/linkedin-accounts/{id} _Requires the `channels:write` scope (or a broader one that includes it)._ Deletes a LinkedIn account by ID. Use the force parameter to delete accounts that are in use by sequences. # Delete a pending LinkedIn account Source: https://docs.reply.io/api-reference/linkedin-accounts/delete-a-pending-linkedin-account /api-reference/bundled.yaml delete /v3/linkedin-accounts/pending/{id} _Requires the `channels:write` scope (or a broader one that includes it)._ Deletes a pending LinkedIn account that has not yet been connected. # Get a LinkedIn account Source: https://docs.reply.io/api-reference/linkedin-accounts/get-a-linkedin-account /api-reference/bundled.yaml get /v3/linkedin-accounts/{id} _Requires the `channels:read` scope (or a broader one that includes it)._ Returns a single LinkedIn account by ID. # List LinkedIn accounts Source: https://docs.reply.io/api-reference/linkedin-accounts/list-linkedin-accounts /api-reference/bundled.yaml get /v3/linkedin-accounts _Requires the `channels:read` scope (or a broader one that includes it)._ Returns all LinkedIn accounts for the authenticated user. # List pending LinkedIn accounts Source: https://docs.reply.io/api-reference/linkedin-accounts/list-pending-linkedin-accounts /api-reference/bundled.yaml get /v3/linkedin-accounts/pending _Requires the `channels:read` scope (or a broader one that includes it)._ Returns all pending LinkedIn accounts that are awaiting connection. # Reconnect a LinkedIn account Source: https://docs.reply.io/api-reference/linkedin-accounts/reconnect-a-linkedin-account /api-reference/bundled.yaml post /v3/linkedin-accounts/{id}/reconnect _Requires the `channels:write` scope (or a broader one that includes it)._ Generates a new connection link for reconnecting an existing LinkedIn account whose cookie has expired. # Toggle LinkedIn account status Source: https://docs.reply.io/api-reference/linkedin-accounts/toggle-linkedin-account-status /api-reference/bundled.yaml post /v3/linkedin-accounts/{id}/toggle-status _Requires the `channels:operate` scope (or a broader one that includes it)._ Toggles the enabled/disabled status of a LinkedIn account. # Update LinkedIn account limits Source: https://docs.reply.io/api-reference/linkedin-accounts/update-linkedin-account-limits /api-reference/bundled.yaml put /v3/linkedin-accounts/{id}/limits _Requires the `channels:operate` scope (or a broader one that includes it)._ Updates the daily automation limits for a LinkedIn account. # Update LinkedIn account revoke settings Source: https://docs.reply.io/api-reference/linkedin-accounts/update-linkedin-account-revoke-settings /api-reference/bundled.yaml put /v3/linkedin-accounts/{id}/revoke-settings _Requires the `channels:write` scope (or a broader one that includes it)._ Updates the automatic connection revocation settings for a LinkedIn account. # Departments typeahead Source: https://docs.reply.io/api-reference/live-data/departments-typeahead /api-reference/bundled.yaml get /v3/live-data/filter-values/departments **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:read` scope (or a broader one that includes it)._ Typeahead values for the `departments` filter on the Live Data / Autopilot sidebar. # Get a Live Data search Source: https://docs.reply.io/api-reference/live-data/get-a-live-data-search /api-reference/bundled.yaml get /v3/live-data/searches/{id} **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a single Live Data search by id, including its status, progress, and the filters it was run with. # Industries typeahead Source: https://docs.reply.io/api-reference/live-data/industries-typeahead /api-reference/bundled.yaml get /v3/live-data/filter-values/industries **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:read` scope (or a broader one that includes it)._ Typeahead values for the `industries` filter on the Live Data / Autopilot sidebar. # Job titles typeahead Source: https://docs.reply.io/api-reference/live-data/job-titles-typeahead /api-reference/bundled.yaml get /v3/live-data/filter-values/job-titles **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:read` scope (or a broader one that includes it)._ Typeahead values for the `jobTitles` filter on the Live Data / Autopilot sidebar. # List Live Data searches Source: https://docs.reply.io/api-reference/live-data/list-live-data-searches /api-reference/bundled.yaml get /v3/live-data/searches **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:read` scope (or a broader one that includes it)._ Returns a paginated list of past Live Data searches for the caller's team, most recent first. Each item includes status and progress for polling. # Locations typeahead Source: https://docs.reply.io/api-reference/live-data/locations-typeahead /api-reference/bundled.yaml get /v3/live-data/filter-values/locations **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:read` scope (or a broader one that includes it)._ Typeahead values for the `locations` filter on the Live Data / Autopilot sidebar. The response mixes countries, regions, and cities (no separate `/countries` endpoint). # Preview a Live Data search Source: https://docs.reply.io/api-reference/live-data/preview-a-live-data-search /api-reference/bundled.yaml post /v3/live-data/searches/preview **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:write` scope (or a broader one that includes it)._ Starts a Live Data preview for the given filters and returns a background job to poll. The job is tracked by `GET /v3/background-jobs/{id}`; on completion its `jsonDataResult` carries `{ contactsCount, companiesCount, sampleContacts }`, where `sampleContacts` is a capped sample of matching contacts. A preview adds no prospects and consumes no credits. # Seniorities typeahead Source: https://docs.reply.io/api-reference/live-data/seniorities-typeahead /api-reference/bundled.yaml get /v3/live-data/filter-values/seniorities **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:read` scope (or a broader one that includes it)._ Typeahead values for the `seniorities` filter on the Live Data / Autopilot sidebar. # Start a Live Data search Source: https://docs.reply.io/api-reference/live-data/start-a-live-data-search /api-reference/bundled.yaml post /v3/live-data/searches **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `contacts:write` scope (or a broader one that includes it)._ Starts a Live Data search that finds contacts matching the filters and adds them as prospects (optionally moving them into a sequence and/or lists). Consumes credits from the Reply credit pool per resulting contact. Returns the created search's id; track its progress via `GET /v3/live-data/searches/{id}`. # Get calls reporting overview Source: https://docs.reply.io/api-reference/reports/get-calls-reporting-overview /api-reference/bundled.yaml post /v3/reporting/calls/overview _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns aggregated call statistics with per-member breakdown. Includes total calls, average duration, positive/answered counts, and inbound missing calls. # Get channel efficiency overview Source: https://docs.reply.io/api-reference/reports/get-channel-efficiency-overview /api-reference/bundled.yaml post /v3/reporting/channel-efficiency/overview _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns cross-channel efficiency statistics comparing performance across email, calls, LinkedIn, and other channels. # Get email reporting overview Source: https://docs.reply.io/api-reference/reports/get-email-reporting-overview /api-reference/bundled.yaml post /v3/reporting/emails/overview _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns email delivery and engagement metrics with optional trend comparison. Provides aggregated statistics including delivery rates, opens, replies, bounces, and clicks. Optionally compare against a previous period by providing the `compareTo` field. # Get LinkedIn reporting overview Source: https://docs.reply.io/api-reference/reports/get-linkedin-reporting-overview /api-reference/bundled.yaml post /v3/reporting/linkedin/overview _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns LinkedIn engagement metrics overview including connection requests, messages, InMails, and profile views. # Get tasks reporting overview Source: https://docs.reply.io/api-reference/reports/get-tasks-reporting-overview /api-reference/bundled.yaml post /v3/reporting/tasks/overview _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns aggregated task statistics broken down by type (call, email, LinkedIn, meetings, SMS, to-do, WhatsApp), with per-member breakdown. # Get team performance overview Source: https://docs.reply.io/api-reference/reports/get-team-performance-overview /api-reference/bundled.yaml post /v3/reporting/team-performance/overview _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns team performance metrics including meetings booked, contacts engaged, conversion rates, touches per contact, and response times, with per-member breakdown. # List call activity Source: https://docs.reply.io/api-reference/reports/list-call-activity /api-reference/bundled.yaml post /v3/reporting/calls _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns a paginated list of individual call records matching the specified filters. Call recording URLs are included only if the user has permission to listen to call records. # List email activity Source: https://docs.reply.io/api-reference/reports/list-email-activity /api-reference/bundled.yaml post /v3/reporting/emails _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns a paginated list of individual email activity records matching the specified filters. Use `top` and `skip` query parameters for pagination. # List LinkedIn activity Source: https://docs.reply.io/api-reference/reports/list-linkedin-activity /api-reference/bundled.yaml post /v3/reporting/linkedin _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns a paginated list of individual LinkedIn action records matching the specified filters. # List meetings Source: https://docs.reply.io/api-reference/reports/list-meetings /api-reference/bundled.yaml post /v3/reporting/team-performance/meetings _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns a paginated list of meetings booked through team performance, matching the specified filters. # List task activity Source: https://docs.reply.io/api-reference/reports/list-task-activity /api-reference/bundled.yaml post /v3/reporting/tasks _Requires the `reporting:read` scope (or a broader one that includes it)._ Returns a paginated list of individual task records matching the specified filters. # Create a schedule Source: https://docs.reply.io/api-reference/schedules/create-a-schedule /api-reference/bundled.yaml post /v3/schedules _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new schedule with timing configuration. # Delete a schedule Source: https://docs.reply.io/api-reference/schedules/delete-a-schedule /api-reference/bundled.yaml delete /v3/schedules/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes a schedule by ID. Cannot delete the default schedule or a schedule in use. # Get a schedule Source: https://docs.reply.io/api-reference/schedules/get-a-schedule /api-reference/bundled.yaml get /v3/schedules/{id} _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a single schedule by ID. # Link a holiday calendar to a schedule Source: https://docs.reply.io/api-reference/schedules/link-a-holiday-calendar-to-a-schedule /api-reference/bundled.yaml post /v3/schedules/{id}/holiday-calendar-links _Requires the `sequences:operate` scope (or a broader one that includes it)._ Links a holiday calendar to the specified schedule. # List linked holiday calendars Source: https://docs.reply.io/api-reference/schedules/list-linked-holiday-calendars /api-reference/bundled.yaml get /v3/schedules/{id}/holiday-calendars _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns all holiday calendars linked to the specified schedule. # List schedules Source: https://docs.reply.io/api-reference/schedules/list-schedules /api-reference/bundled.yaml get /v3/schedules _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns all schedules for the authenticated user. # Set default schedule Source: https://docs.reply.io/api-reference/schedules/set-default-schedule /api-reference/bundled.yaml post /v3/schedules/{id}/set-default _Requires the `sequences:operate` scope (or a broader one that includes it)._ Sets the specified schedule as the default. # Unlink a holiday calendar from a schedule Source: https://docs.reply.io/api-reference/schedules/unlink-a-holiday-calendar-from-a-schedule /api-reference/bundled.yaml delete /v3/schedules/{id}/holiday-calendar-links/{calendarId} _Requires the `sequences:operate` scope (or a broader one that includes it)._ Removes the link between a holiday calendar and the specified schedule. # Update a schedule Source: https://docs.reply.io/api-reference/schedules/update-a-schedule /api-reference/bundled.yaml put /v3/schedules/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Updates an existing schedule. # Count contacts in sequence Source: https://docs.reply.io/api-reference/sequence-contacts/count-contacts-in-sequence /api-reference/bundled.yaml get /v3/sequences/{id}/contacts/count **Coming soon.** This endpoint will be available by late August 2026. _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns the total number of contacts enrolled in the sequence. # List contacts in sequence Source: https://docs.reply.io/api-reference/sequence-contacts/list-contacts-in-sequence /api-reference/bundled.yaml get /v3/sequences/{id}/contacts _Requires the `sequences:read` scope (or a broader one that includes it)._ Retrieve all contacts enrolled in the sequence. Defaults to most-recently-added first; use `sort_by` and `sort_direction` to override. # Archive a sequence Source: https://docs.reply.io/api-reference/sequences/archive-a-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/archive _Requires the `sequences:operate` scope (or a broader one that includes it)._ Archives a sequence. Returns the updated sequence. # Bulk archive sequences Source: https://docs.reply.io/api-reference/sequences/bulk-archive-sequences /api-reference/bundled.yaml post /v3/sequences/archive _Requires the `sequences:write` scope (or a broader one that includes it)._ Archives multiple sequences at once. Non-atomic — some may succeed while others fail. # Bulk change sequence owner Source: https://docs.reply.io/api-reference/sequences/bulk-change-sequence-owner /api-reference/bundled.yaml post /v3/sequences/batch/owner _Requires the `sequences:write` scope (or a broader one that includes it)._ Changes the owner of multiple sequences at once. Non-atomic — some may succeed while others fail. # Bulk delete sequences Source: https://docs.reply.io/api-reference/sequences/bulk-delete-sequences /api-reference/bundled.yaml post /v3/sequences/bulk-delete _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes multiple sequences at once. Non-atomic — some may succeed while others fail. # Bulk pause sequences Source: https://docs.reply.io/api-reference/sequences/bulk-pause-sequences /api-reference/bundled.yaml post /v3/sequences/pause _Requires the `sequences:operate` scope (or a broader one that includes it)._ Pauses multiple sequences at once. Non-atomic — some may succeed while others fail. # Bulk start sequences Source: https://docs.reply.io/api-reference/sequences/bulk-start-sequences /api-reference/bundled.yaml post /v3/sequences/start _Requires the `sequences:operate` scope (or a broader one that includes it)._ Starts multiple sequences at once. Non-atomic — some may succeed while others fail. # Bulk unarchive sequences Source: https://docs.reply.io/api-reference/sequences/bulk-unarchive-sequences /api-reference/bundled.yaml post /v3/sequences/unarchive **Coming soon.** This endpoint will be available by late August 2026. _Requires the `sequences:write` scope (or a broader one that includes it)._ Unarchives multiple sequences at once. Non-atomic — some may succeed while others fail. # Change sequence owner Source: https://docs.reply.io/api-reference/sequences/change-sequence-owner /api-reference/bundled.yaml put /v3/sequences/{id}/owner _Requires the `sequences:write` scope (or a broader one that includes it)._ Changes the owner of a single sequence to a different team member # Count sequences Source: https://docs.reply.io/api-reference/sequences/count-sequences /api-reference/bundled.yaml get /v3/sequences/count **Coming soon.** This endpoint will be available by late August 2026. _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns the total number of sequences matching the given filters. Accepts the same filter parameters as `GET /v3/sequences` (except pagination and sorting). # Create a sequence Source: https://docs.reply.io/api-reference/sequences/create-a-sequence /api-reference/bundled.yaml post /v3/sequences _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new email sequence # Create a sequence from a template Source: https://docs.reply.io/api-reference/sequences/create-a-sequence-from-a-template /api-reference/bundled.yaml post /v3/sequences/create-from-template _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new sequence based on an existing sequence template # Delete a sequence Source: https://docs.reply.io/api-reference/sequences/delete-a-sequence /api-reference/bundled.yaml delete /v3/sequences/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes an existing sequence # Get a sequence Source: https://docs.reply.io/api-reference/sequences/get-a-sequence /api-reference/bundled.yaml get /v3/sequences/{id} _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns sequence details by Id # Get sequence stats Source: https://docs.reply.io/api-reference/sequences/get-sequence-stats /api-reference/bundled.yaml post /v3/sequences/{id}/stats _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns aggregated email and LinkedIn engagement stats for a single sequence. # Get stats for all sequences Source: https://docs.reply.io/api-reference/sequences/get-stats-for-all-sequences /api-reference/bundled.yaml post /v3/sequences/stats _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns email and LinkedIn engagement stats per sequence. **Date range restrictions:** - `dateRangePreset` must be `lastWeek` or `lastMonth`. `lastYear` and `allTime` are rejected. - When using `from`/`to`, the span must not exceed 31 days. - `from` must be within the last 31 days from the current date. - Defaults to `lastWeek` if no date filters are provided. # List all sequences Source: https://docs.reply.io/api-reference/sequences/list-all-sequences /api-reference/bundled.yaml get /v3/sequences _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a paginated list of all sequences in your account. Results are ordered by creation date, newest first, unless overridden with `sortBy` / `sortDirection`. # Pause a sequence Source: https://docs.reply.io/api-reference/sequences/pause-a-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/pause _Requires the `sequences:operate` scope (or a broader one that includes it)._ Pauses an active sequence. Returns the updated sequence. This operation is **idempotent**: calling Pause on an already paused sequence returns `200` with the current sequence state. No error is raised. # Save a sequence as a template Source: https://docs.reply.io/api-reference/sequences/save-a-sequence-as-a-template /api-reference/bundled.yaml post /v3/sequences/{id}/save-as-template _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new sequence template from an existing sequence # Start a sequence Source: https://docs.reply.io/api-reference/sequences/start-a-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/start _Requires the `sequences:operate` scope (or a broader one that includes it)._ Activates a new or paused sequence. Returns the updated sequence. This operation is **idempotent**: calling Start on an already active sequence returns `200` with the current sequence state. No error is raised. # Unarchive a sequence Source: https://docs.reply.io/api-reference/sequences/unarchive-a-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/unarchive **Coming soon.** This endpoint will be available by late August 2026. _Requires the `sequences:operate` scope (or a broader one that includes it)._ Restores an archived sequence to its previous state. Returns the updated sequence. # Update a sequence Source: https://docs.reply.io/api-reference/sequences/update-a-sequence /api-reference/bundled.yaml patch /v3/sequences/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Updates an existing sequence # Machine-readable indexes Source: https://docs.reply.io/agents/machine-readable llms.txt, OpenAPI, catalog.json, and runtime discovery — how agents read Reply.io documentation programmatically. Every layer of Reply.io documentation is available in a machine-readable form. Use these instead of scraping HTML. ## This site (docs.reply.io) | Resource | URL | What it is | | ------------- | ------------------------------------------------------- | -------------------------------------------------------------------------- | | llms.txt | [`/llms.txt`](https://docs.reply.io/llms.txt) | Index of all documentation pages with descriptions | | llms-full.txt | [`/llms-full.txt`](https://docs.reply.io/llms-full.txt) | The full documentation content in one file | | OpenAPI spec | see [OpenAPI & Postman](/openapi-postman) | The complete v3 REST API specification (also drives the API Reference tab) | Mintlify also serves any docs page as markdown — append `.md` to a page URL for the raw source. ## The agents portal (agents.reply.io) The [agent discovery portal](https://agents.reply.io) publishes its own machine surface, useful as a compact capability index before diving into full references here: | Resource | What it is | | ------------------------------ | ---------------------------------------------------------------------------------------- | | `/catalog.json` | Machine-readable module index: modules, workflows, auth model, rate limits, MCP endpoint | | `/llms.txt` · `/llms-full.txt` | Portal content index and full text | | `.md` twins | Every portal page is also plain markdown — append `.md` to its URL | | Per-module OpenAPI | Small, module-scoped OpenAPI subsets — lighter than the full spec for narrow tasks | The portal is a discovery layer; canonical technical facts live here on docs.reply.io. ## Runtime discovery Two sources are always current because they come from the running systems: * **MCP `tools/list`** — the live tool catalog with full JSON schemas and safety annotations. This is the runtime truth for MCP; regenerate the reference any time — see [Tool reference](/mcp/tools#regenerate-this-reference). * **CLI `--help`** — `reply --help` and `reply --help` print flags and examples, matching the installed version exactly. ## Recommended agent reading order 1. `docs.reply.io/llms.txt` — find the relevant pages. 2. The specific page as `.md` — read only what the task needs. 3. For MCP work: `tools/list` on the live server for exact schemas. 4. For REST work: the [OpenAPI spec](/openapi-postman) for exact request/response shapes. # Schemas Source: https://docs.reply.io/api-reference/schemas Object models used across the Reply API v3, grouped by resource domain. Reference for the objects the Reply API v3 accepts and returns. Each entry links to a dedicated page with the full field list, types, and descriptions. ## Contacts & lists | Schema | Description | | ------------------------------------------------------------------------- | ------------------------------------------------------------------ | | [Account Filter Item](/api-reference/schemas/contact-account-filter-item) | A single filter condition for contact account queries | | [Contact](/api-reference/schemas/contact) | Contact response model | | [Contact Account](/api-reference/schemas/contact-account) | A contact account representing a company or organization | | [Contact Account Contact](/api-reference/schemas/contact-account-contact) | A contact linked to a contact account | | [Contact Account Details](/api-reference/schemas/contact-account-details) | A single contact account, including the resolved email provider | | [Contact Account List](/api-reference/schemas/contact-account-list) | Account list entity | | [Contact Account Stage](/api-reference/schemas/contact-account-stage) | Stage assigned to a contact account | | [Contact Inbox Thread](/api-reference/schemas/contact-inbox-thread) | Inbox thread summary as it appears on a single contact's timeline. | | [Contact List](/api-reference/schemas/contact-list) | Contact list entity | | [Contact List Reference](/api-reference/schemas/contact-list-ref) | Lightweight contact list reference | ## Sequences | Schema | Description | | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | [AI SDR sequence settings](/api-reference/schemas/sequence) | AI SDR-specific settings of a sequence. | | [Sequence](/api-reference/schemas/sequence-response) | Full representation of a sequence, including its schedule and the email and LinkedIn accounts used to send from it. | | [Sequence Contact](/api-reference/schemas/sequence-contact-item) | A contact enrolled in a sequence with sequence-specific metadata | | [Sequence Contacts List](/api-reference/schemas/sequence-contact) | Response model for listing contacts in a sequence with pagination | | [Sequence Contacts List with Extended State](/api-reference/schemas/sequence-contact-state) | Response model for listing contacts in a sequence with pagination, including extended state columns | | [Sequence Email Account](/api-reference/schemas/sequence-email-account) | An email account linked to a sequence for sending outbound emails. | | [Sequence Folder](/api-reference/schemas/sequence-folder) | A folder for organizing sequences | | [Sequence LinkedIn Account](/api-reference/schemas/sequence-linkedin-account) | A LinkedIn account linked to a sequence | | [Sequence Step Info](/api-reference/schemas/sequence-step-info) | Position of the contact within a sequence's step graph. | | [Sequence Template](/api-reference/schemas/sequence-template-base) | A sequence template | | [Sequence Templates List](/api-reference/schemas/sequence-templates-list) | Response model for listing sequence templates grouped by scope | | [Step Variant](/api-reference/schemas/variant) | A text variant for a sequence step | ## Email accounts | Schema | Description | | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | [Email Account Detail](/api-reference/schemas/email-account-detail) | Full detailed representation of an email account, including all configuration sections. | | [Email Account Stats](/api-reference/schemas/email-account-stats) | | | [Email Account Tag](/api-reference/schemas/email-account-tag) | An email account tag used for organizing and filtering accounts. | ## Email templates | Schema | Description | | ----------------------------------------------------------------------------- | ----------------------------------------------------------------- | | [Email Template](/api-reference/schemas/email-template) | Full representation of an email template including timestamps. | | [Email Template Attachment](/api-reference/schemas/email-template-attachment) | Attachment associated with an email template. | | [Email Template Folder](/api-reference/schemas/email-template-folder) | An email template folder for organizing templates. | | [Email Template Variables](/api-reference/schemas/email-template-variables) | Available template variables grouped by category. | | [Render Error](/api-reference/schemas/email-template-render-error) | An error encountered during template rendering. | | [Render Template Result](/api-reference/schemas/email-template-render-result) | Result of rendering an email template with variable substitution. | | [Variable Info](/api-reference/schemas/email-template-variable-info) | Information about a single template variable. | ## Inbox | Schema | Description | | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | [Inbox Category](/api-reference/schemas/category) | Inbox thread category. | | [Inbox Thread](/api-reference/schemas/thread) | Full inbox thread with the contact, channel-specific account ids, sequence, category, meeting-intent flag, and the ordered list of messages. | | [Inbox Thread AI Draft](/api-reference/schemas/thread-ai-draft) | The thread's pending AI-drafted reply, awaiting review. | | [Inbox Thread Category Reference](/api-reference/schemas/thread-category) | Minimal category reference embedded in thread responses. | | [Inbox Thread Contact](/api-reference/schemas/thread-contact) | Contact party on the other end of an inbox thread. | | [Inbox Thread Message Status](/api-reference/schemas/thread-message-status) | Per-message status. | | [Inbox Thread Sequence](/api-reference/schemas/thread-sequence) | Minimal sequence reference attached to an inbox thread. | | [Inbox Thread Status](/api-reference/schemas/thread-status) | Aggregated thread state, derived from the latest message. | ## Tasks | Schema | Description | | -------------------------------------------- | --------------------------------------------------------------------- | | [Task](/api-reference/schemas/task-response) | Full task detail returned by GET by ID, Create, and Update endpoints. | ## LinkedIn | Schema | Description | | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | [Connection Link](/api-reference/schemas/connection-link) | A link for connecting a LinkedIn account via browser extension. | | [Connection Link With Pending](/api-reference/schemas/connection-link-with-pending) | A connection link with the associated pending account ID. | | [LinkedIn Account](/api-reference/schemas/linkedin-account) | Full representation of a LinkedIn account. | | [LinkedIn Account Limits](/api-reference/schemas/linkedin-account-limits) | Daily limits configuration for a LinkedIn account. | | [LinkedIn Account Limits Values](/api-reference/schemas/linkedin-account-limits-values) | Individual daily limit values for LinkedIn automation actions. | | [LinkedIn Account Revoke Settings](/api-reference/schemas/linkedin-account-revoke-settings) | Connection revocation settings for a LinkedIn account. | | [LinkedIn Account Toggle Status](/api-reference/schemas/linkedin-account-toggle-status) | Response after toggling a LinkedIn account status. | | [LinkedIn Account Usage](/api-reference/schemas/linkedin-account-usage) | Daily usage statistics for a LinkedIn account. | | [LinkedIn Account Voice Profile](/api-reference/schemas/linkedin-account-voice-profile) | Voice profile associated with a LinkedIn account. | | [LinkedIn Action Item](/api-reference/schemas/linkedin-action-item) | Individual LinkedIn action record in a reporting list | | [Pending LinkedIn Account](/api-reference/schemas/pending-linkedin-account) | A LinkedIn account that is pending connection. | ## Schedules & holidays | Schema | Description | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | [Holiday](/api-reference/schemas/holiday) | A single holiday entry within a calendar. | | [Holiday Calendar](/api-reference/schemas/holiday-calendar) | Full representation of a holiday calendar including individual holidays. | | [Holiday Input](/api-reference/schemas/holiday-input) | A holiday entry for creating or updating a calendar. | | [Schedule](/api-reference/schemas/schedule) | Full representation of a schedule with timing configuration. | | [Schedule Time](/api-reference/schemas/schedule-time) | A time of day represented as hour and minute. | | [Schedule Timing](/api-reference/schemas/schedule-timing) | Timing configuration for a single day of the week. | | [Schedule Timing Time Range](/api-reference/schemas/schedule-timing-time-range) | A time range within a day. | ## Blocklist rules | Schema | Description | | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | [Domain Blacklist Rule](/api-reference/schemas/domain-rule) | A blacklist rule that blocks a domain pattern | | [Email Blacklist Rule](/api-reference/schemas/email-rule) | A blacklist rule that blocks an email pattern | | [Email Exception Blacklist Rule](/api-reference/schemas/email-exception-rule) | An exception rule that allows an email pattern even if it matches a blacklist rule | ## AI SDR | Schema | Description | | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | [Knowledge Base](/api-reference/schemas/knowledge-base) | Detailed representation of a knowledge base. | | [Knowledge Base Document](/api-reference/schemas/knowledge-base-document) | A file document attached to a knowledge base. | | [Knowledge Base Link](/api-reference/schemas/knowledge-base-link) | A web link attached to a knowledge base. | | [Knowledge Base Media](/api-reference/schemas/knowledge-base-media) | A media file attached to a reply handler or reengagement card. | | [Offer](/api-reference/schemas/offer) | Detailed representation of an offer — the bundle of company-context inputs the AI SDR uses to personalize outreach. | | [Playbook](/api-reference/schemas/playbook) | Detailed representation of a playbook, returned by get/create/update responses. | | [Playbook Style File](/api-reference/schemas/playbook-style-file) | A single style file attached to a playbook. | | [Reengagement Card](/api-reference/schemas/reengagement-card) | Detailed representation of a reengagement card. | | [Reply Handler](/api-reference/schemas/reply-handler) | Detailed representation of a reply handler. | ## Reports & analytics | Schema | Description | | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | [Calls Overview Response](/api-reference/schemas/calls-overview-response) | Aggregated call statistics with per-member breakdown | | [Channel Efficiency Overview Response](/api-reference/schemas/channel-efficiency-overview-response) | Cross-channel efficiency statistics | | [Emails Overview Response](/api-reference/schemas/emails-overview-response) | Email delivery and engagement metrics | | [LinkedIn Overview Response](/api-reference/schemas/linkedin-overview-response) | LinkedIn engagement metrics overview | | [Sequence Stats Response](/api-reference/schemas/sequence-stats-response) | Aggregated email and LinkedIn stats for a single sequence | | [Tasks Overview Response](/api-reference/schemas/tasks-overview-response) | Aggregated task statistics broken down by type, with per-member breakdown | | [Team Performance Overview Response](/api-reference/schemas/team-performance-overview-response) | Team performance metrics including meetings, contacts, and engagement rates | ## Live data | Schema | Description | | ----------------------------------------------------------------- | ----------------------------------------------------------------- | | [Live Data search](/api-reference/schemas/search) | Summary of a Live Data search. | | [Live Data search details](/api-reference/schemas/search-details) | A single Live Data search, including the filters it was run with. | ## Attachments | Schema | Description | | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | [Attachment](/api-reference/schemas/attachment) | Uploaded file attachment usable across email templates, sequence steps, and direct emails. | | [Voice Attachment](/api-reference/schemas/voice-attachment) | Uploaded voice message attachment. | ## Background jobs | Schema | Description | | ------------------------------------------------------- | ------------------------------------------------------- | | [Background Job](/api-reference/schemas/background-job) | A long-running background operation tracked by the API. | ## Webhooks | Schema | Description | | ------------------------------------------------------- | -------------------------------------------------------------------- | | [Webhook](/api-reference/schemas/webhook) | A webhook subscription. | | [Webhook Events](/api-reference/schemas/webhook-events) | Catalog of event types that a webhook subscription can subscribe to. | | [Webhook Log](/api-reference/schemas/webhook-log) | One delivery-attempt record for a webhook subscription. | ## Common | Schema | Description | | ----------------------------------------------------------------------------- | ------------------------------------------------------ | | [Create Item Result](/api-reference/schemas/create-item-result) | Per-item result for non-atomic bulk create operations. | | [Not Processed Item Result](/api-reference/schemas/not-processed-item-result) | Per-item error for non-atomic bulk operations. | | [Validation Error](/api-reference/schemas/validation-error) | A single field-level validation error. | | [Validation Problem](/api-reference/schemas/validation-problem) | Input-validation error response at 400. | ## Other | Schema | Description | | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | [Business Problem](/api-reference/schemas/business-problem) | Domain error response carrying a stable, namespaced error slug. | | [Count Result](/api-reference/schemas/count-result) | | | [Custom Field](/api-reference/schemas/custom-field) | A user-defined field for storing additional data on contacts. | | [Email Validation Estimate](/api-reference/schemas/email-validation-estimate-response) | Synchronous probe result returned by `/v3/email-validations/estimate`. | | [Email Validation Schedule](/api-reference/schemas/email-validation-schedule-response) | Acknowledgement returned by `/v3/email-validations/schedule`. | | [Intent Signal Industry](/api-reference/schemas/intent-industry-item) | A single industry entry from the typeahead list, used in intent-signal configuration. | | [Intent Signal Technology](/api-reference/schemas/intent-technology-item) | A single technology entry from the typeahead list, used in intent-signal configuration. | | [Problem Details](/api-reference/schemas/problem-details) | Bare RFC 9457 problem-details envelope. | | [Settings](/api-reference/schemas/settings) | Team and user settings. | # Bulk add contacts to sequence Source: https://docs.reply.io/api-reference/sequence-contacts/bulk-add-contacts-to-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/contact-links/bulk _Requires the `sequences:operate` scope (or a broader one that includes it)._ Add multiple contacts to the sequence at once # Bulk remove contacts from sequence Source: https://docs.reply.io/api-reference/sequence-contacts/bulk-remove-contacts-from-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/contact-links/bulk-delete _Requires the `sequences:operate` scope (or a broader one that includes it)._ Remove multiple contacts from the sequence at once # Get a contact in a sequence Source: https://docs.reply.io/api-reference/sequence-contacts/get-a-contact-in-a-sequence /api-reference/bundled.yaml get /v3/sequences/{id}/contacts/{contact_id} _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns details of a specific contact enrolled in the sequence. # Get sequence preview for a contact Source: https://docs.reply.io/api-reference/sequence-contacts/get-sequence-preview-for-a-contact /api-reference/bundled.yaml get /v3/sequences/{sequence_id}/contacts/{contact_id}/preview **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns the per-contact preview of the messages this sequence will send, including any AI-personalized step templates. # List contacts in sequence with extended state Source: https://docs.reply.io/api-reference/sequence-contacts/list-contacts-in-sequence-with-extended-state /api-reference/bundled.yaml get /v3/sequences/{id}/contacts/state _Requires the `sequences:read` scope (or a broader one that includes it)._ Retrieve contacts enrolled in the sequence with optional additional columns such as current step, last step completed at, and status. The response always includes the base fields: `contactId`, `email`, `firstName`, `lastName`, `title`, `addedAt`. Additional fields (`currentStep`, `lastStepCompletedAt`, `status`) are **only** included when explicitly requested via the `additionalColumns` query parameter. Omitting `additionalColumns` returns only the base fields. # Mark or unmark contacts as bounced in this sequence Source: https://docs.reply.io/api-reference/sequence-contacts/mark-or-unmark-contacts-as-bounced-in-this-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/contacts/set-bounced _Requires the `sequences:operate` scope (or a broader one that includes it)._ Marks the given contacts as bounced (`isBounced: true`) or clears the bounced flag (`isBounced: false`), scoped to **this sequence only**. When clearing the flag (`isBounced: false`), `resendEmails` is required: pass `true` to retry the previously bounced step or `false` to leave the schedule untouched. When marking as bounced (`isBounced: true`), `resendEmails` must be omitted. To apply across every sequence a contact is in, use `POST /v3/contacts/set-bounced` instead. # Mark or unmark contacts as replied in this sequence Source: https://docs.reply.io/api-reference/sequence-contacts/mark-or-unmark-contacts-as-replied-in-this-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/contacts/set-replied _Requires the `sequences:operate` scope (or a broader one that includes it)._ Marks the given contacts as replied (`isReplied: true`) or clears the replied flag (`isReplied: false`), scoped to **this sequence only**. To apply across every sequence a contact is in, use `POST /v3/contacts/set-replied` instead. # Remove contact from sequence Source: https://docs.reply.io/api-reference/sequence-contacts/remove-contact-from-sequence /api-reference/bundled.yaml delete /v3/sequences/{id}/contact-links/{contact_id} _Requires the `sequences:operate` scope (or a broader one that includes it)._ Remove a contact from the sequence # Reset manual edits in a sequence preview Source: https://docs.reply.io/api-reference/sequence-contacts/reset-manual-edits-in-a-sequence-preview /api-reference/bundled.yaml post /v3/sequences/{sequence_id}/contacts/{contact_id}/preview/reset **Beta.** This endpoint is in beta. Behavior, parameters, and response shapes may change without notice. _Requires the `sequences:operate` scope (or a broader one that includes it)._ Reverts any manual edits the user has made to the preview for a contact and restores the AI-generated templates. # Set contacts' status in this sequence Source: https://docs.reply.io/api-reference/sequence-contacts/set-contacts-status-in-this-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/contacts/set-status-in-sequence _Requires the `sequences:operate` scope (or a broader one that includes it)._ Sets the in-sequence status (`active` / `paused` / `finished` / `outOfOffice`) for the given contacts, scoped to **this sequence only**. To apply across every sequence a contact is in, use `POST /v3/contacts/set-status-in-sequence` instead. Replied and Bounced are **not** values of this enum — use `POST /v3/sequences/{id}/contacts/set-replied` or `POST /v3/sequences/{id}/contacts/set-bounced` for those. `paused` requires the contact to currently be `active` in this sequence — pausing from any other state is reported per-item as `invalidStatusTransition`. The other targets (`active`, `finished`, `outOfOffice`) accept any current state. # Assign email account to sequence Source: https://docs.reply.io/api-reference/sequence-email-accounts/assign-email-account-to-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/email-account-links _Requires the `sequences:operate` scope (or a broader one that includes it)._ Links an email account to the sequence so it can be used for sending outbound emails. # List email accounts in sequence Source: https://docs.reply.io/api-reference/sequence-email-accounts/list-email-accounts-in-sequence /api-reference/bundled.yaml get /v3/sequences/{id}/email-accounts _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns the list of email accounts currently linked to the specified sequence. # Remove email account from sequence Source: https://docs.reply.io/api-reference/sequence-email-accounts/remove-email-account-from-sequence /api-reference/bundled.yaml delete /v3/sequences/{id}/email-account-links/{email_account_id} _Requires the `sequences:operate` scope (or a broader one that includes it)._ Unlinks an email account from the sequence. The email account itself is not deleted. # Set sequence email accounts Source: https://docs.reply.io/api-reference/sequence-email-accounts/set-sequence-email-accounts /api-reference/bundled.yaml put /v3/sequences/{id}/email-account-links _Requires the `sequences:operate` scope (or a broader one that includes it)._ Replaces all email account links for the sequence with the provided list. Any previously linked accounts not in the new list will be unlinked. # Bulk assign sequences to a folder Source: https://docs.reply.io/api-reference/sequence-folders/bulk-assign-sequences-to-a-folder /api-reference/bundled.yaml post /v3/sequence-folders/{id}/sequence-links/bulk _Requires the `sequences:operate` scope (or a broader one that includes it)._ Assigns multiple sequences to a folder. Returns a map of sequence IDs that could not be processed with their error details. # Bulk unassign sequences from a folder Source: https://docs.reply.io/api-reference/sequence-folders/bulk-unassign-sequences-from-a-folder /api-reference/bundled.yaml post /v3/sequence-folders/{id}/sequence-links/bulk-delete _Requires the `sequences:operate` scope (or a broader one that includes it)._ Removes multiple sequences from a folder. Returns a map of sequence IDs that could not be processed with their error details. # Create a sequence folder Source: https://docs.reply.io/api-reference/sequence-folders/create-a-sequence-folder /api-reference/bundled.yaml post /v3/sequence-folders _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new sequence folder # Delete a sequence folder Source: https://docs.reply.io/api-reference/sequence-folders/delete-a-sequence-folder /api-reference/bundled.yaml delete /v3/sequence-folders/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes an existing sequence folder # Get a sequence folder Source: https://docs.reply.io/api-reference/sequence-folders/get-a-sequence-folder /api-reference/bundled.yaml get /v3/sequence-folders/{id} _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a sequence folder by Id # List all sequence folders Source: https://docs.reply.io/api-reference/sequence-folders/list-all-sequence-folders /api-reference/bundled.yaml get /v3/sequence-folders _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a list of all sequence folders for the current user # List sequences in a folder Source: https://docs.reply.io/api-reference/sequence-folders/list-sequences-in-a-folder /api-reference/bundled.yaml get /v3/sequence-folders/{id}/sequences _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a paginated list of sequences in a folder # Update a sequence folder Source: https://docs.reply.io/api-reference/sequence-folders/update-a-sequence-folder /api-reference/bundled.yaml put /v3/sequence-folders/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Updates an existing sequence folder # Assign a LinkedIn account to a sequence Source: https://docs.reply.io/api-reference/sequence-linkedin-accounts/assign-a-linkedin-account-to-a-sequence /api-reference/bundled.yaml post /v3/sequences/{id}/linkedin-account-links _Requires the `sequences:operate` scope (or a broader one that includes it)._ Links a LinkedIn account to the specified sequence # List LinkedIn accounts for a sequence Source: https://docs.reply.io/api-reference/sequence-linkedin-accounts/list-linkedin-accounts-for-a-sequence /api-reference/bundled.yaml get /v3/sequences/{id}/linkedin-accounts _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns all LinkedIn accounts available for the sequence # Remove a LinkedIn account from a sequence Source: https://docs.reply.io/api-reference/sequence-linkedin-accounts/remove-a-linkedin-account-from-a-sequence /api-reference/bundled.yaml delete /v3/sequences/{id}/linkedin-account-links/{linkedInAccountId} _Requires the `sequences:operate` scope (or a broader one that includes it)._ Unlinks a LinkedIn account from the specified sequence # Bulk create sequence steps Source: https://docs.reply.io/api-reference/sequence-steps/bulk-create-sequence-steps /api-reference/bundled.yaml post /v3/sequences/{id}/steps/bulk _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates multiple steps in a sequence at once. Returns a list of results for each step. Email-step variants may carry up to **3** `attachmentIds` each; inaccessible attachment IDs surface as a per-item `forbidden` result (upload first via `POST /v3/attachments`). # Bulk create step variants Source: https://docs.reply.io/api-reference/sequence-steps/bulk-create-step-variants /api-reference/bundled.yaml post /v3/sequences/{id}/steps/{step_id}/variants/bulk _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates multiple text variants for a sequence step at once. For email steps, each variant may carry up to **3** `attachmentIds` (upload first via `POST /v3/attachments`); inaccessible attachment IDs surface as a per-item `forbidden` result. # Bulk delete sequence steps Source: https://docs.reply.io/api-reference/sequence-steps/bulk-delete-sequence-steps /api-reference/bundled.yaml post /v3/sequences/{id}/steps/bulk-delete _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes multiple steps from a sequence at once. Returns a map of step IDs that could not be processed with their error details. # Bulk delete step variants Source: https://docs.reply.io/api-reference/sequence-steps/bulk-delete-step-variants /api-reference/bundled.yaml post /v3/sequences/{id}/steps/{step_id}/variants/bulk-delete _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes multiple variants from a sequence step at once. Returns a map of variant IDs that could not be processed with their error details. # Create a sequence step Source: https://docs.reply.io/api-reference/sequence-steps/create-a-sequence-step /api-reference/bundled.yaml post /v3/sequences/{id}/steps _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new step in a sequence. For bulk creation, use the `/steps/bulk` endpoint. For email steps, each variant may carry up to **3** `attachmentIds` (upload first via `POST /v3/attachments`); attachments that don't belong to the caller (or the caller's team) are rejected with `403 sequenceStep.forbidden`. # Create a step variant Source: https://docs.reply.io/api-reference/sequence-steps/create-a-step-variant /api-reference/bundled.yaml post /v3/sequences/{id}/steps/{step_id}/variants _Requires the `sequences:write` scope (or a broader one that includes it)._ Creates a new variant for a sequence step. Supports both text variants (`application/json`) and voice message variants (`multipart/form-data`). For email-step text variants, the request may carry up to **3** `attachmentIds` (upload first via `POST /v3/attachments`). Inaccessible attachment IDs are rejected with `403 sequenceStep.forbidden`. # Delete a sequence step Source: https://docs.reply.io/api-reference/sequence-steps/delete-a-sequence-step /api-reference/bundled.yaml delete /v3/sequences/{id}/steps/{step_id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes a sequence step. By default only the addressed step is removed (`mode=nodeOnly`), and any children remain attached to the parent. For condition (branch) steps, set `mode` to also remove descendants on one or both branches. # Delete a step variant Source: https://docs.reply.io/api-reference/sequence-steps/delete-a-step-variant /api-reference/bundled.yaml delete /v3/sequences/{id}/steps/{step_id}/variants/{variant_id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes an existing variant from a sequence step # Disable step variants Source: https://docs.reply.io/api-reference/sequence-steps/disable-step-variants /api-reference/bundled.yaml post /v3/sequences/{id}/steps/{step_id}/disable _Requires the `sequences:operate` scope (or a broader one that includes it)._ Disables the specified variants on a sequence step. Variants are toggled independently — failures are reported per `variantId` in the response without aborting the whole call. # Enable step variants Source: https://docs.reply.io/api-reference/sequence-steps/enable-step-variants /api-reference/bundled.yaml post /v3/sequences/{id}/steps/{step_id}/enable _Requires the `sequences:operate` scope (or a broader one that includes it)._ Enables the specified variants on a sequence step. Variants are toggled independently — failures are reported per `variantId` in the response without aborting the whole call. # Get a sequence step Source: https://docs.reply.io/api-reference/sequence-steps/get-a-sequence-step /api-reference/bundled.yaml get /v3/sequences/{id}/steps/{step_id} _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns details of a specific sequence step # List all sequence steps Source: https://docs.reply.io/api-reference/sequence-steps/list-all-sequence-steps /api-reference/bundled.yaml get /v3/sequences/{id}/steps _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns a list of all steps in a sequence # List contact filter properties Source: https://docs.reply.io/api-reference/sequence-steps/list-contact-filter-properties /api-reference/bundled.yaml get /v3/sequences/steps/contact-filter-properties _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns all available contact filter properties that can be used in sequence step conditions. Each property includes its supported operators and, for enum-like properties, the allowed values. This is a static discovery endpoint — the response does not depend on user data or any specific sequence. # List step variants Source: https://docs.reply.io/api-reference/sequence-steps/list-step-variants /api-reference/bundled.yaml get /v3/sequences/{id}/steps/{step_id}/variants _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns all variants for a sequence step # Update a sequence step Source: https://docs.reply.io/api-reference/sequence-steps/update-a-sequence-step /api-reference/bundled.yaml put /v3/sequences/{id}/steps/{step_id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Updates an existing sequence step. Each variant in the request body must include its `id` to identify which variant to update. For email steps, each variant may carry up to **3** `attachmentIds` (upload first via `POST /v3/attachments`); attachments that don't belong to the caller (or the caller's team) are rejected with `403 sequenceStep.forbidden`. # Update a step variant Source: https://docs.reply.io/api-reference/sequence-steps/update-a-step-variant /api-reference/bundled.yaml put /v3/sequences/{id}/steps/{step_id}/variants/{variant_id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Updates an existing variant for a sequence step. Supports both text variants (`application/json`) and voice message variants (`multipart/form-data`). For email-step text variants, the request may carry up to **3** `attachmentIds` (upload first via `POST /v3/attachments`). Inaccessible attachment IDs are rejected with `403 sequenceStep.forbidden`. # Delete a sequence template Source: https://docs.reply.io/api-reference/sequence-templates/delete-a-sequence-template /api-reference/bundled.yaml delete /v3/sequence-templates/{id} _Requires the `sequences:write` scope (or a broader one that includes it)._ Deletes an existing sequence template. - **Global templates** (seeded by the system) cannot be deleted — returns 403. - **User-scoped templates** are team-shared: any teammate may delete a template visible to them. Out-of-team or non-existent ids return 404. - **Organization templates** require the `DeleteOrgTemplates` feature scope — callers without it get 403. # List all sequence templates Source: https://docs.reply.io/api-reference/sequence-templates/list-all-sequence-templates /api-reference/bundled.yaml get /v3/sequence-templates _Requires the `sequences:read` scope (or a broader one that includes it)._ Returns all sequence templates grouped by scope (global, organization, team) # Get settings Source: https://docs.reply.io/api-reference/settings/get-settings /api-reference/bundled.yaml get /v3/settings _Requires the `settings:read` scope (or a broader one that includes it)._ Returns the full settings object for the authenticated user's team, including account profile, email configuration, LinkedIn, calls, contacts, and beta features. # Update settings Source: https://docs.reply.io/api-reference/settings/update-settings /api-reference/bundled.yaml patch /v3/settings _Requires the `settings:write` scope (or a broader one that includes it)._ Performs a sparse update of settings. Only properties present in the request body are updated — omitted properties are left unchanged. Nested sections follow the same rule: include only the fields you want to change within each section. **Contact stages and account stages** are an exception — when the `contactStages` or `accountStages` array is present, all 8 stages must be provided with unique IDs (1–8). # Batch complete tasks Source: https://docs.reply.io/api-reference/tasks/batch-complete-tasks /api-reference/bundled.yaml post /v3/tasks/batch/complete _Requires the `tasks:operate` scope (or a broader one that includes it)._ Completes multiple tasks without execution. Non-atomic — some may succeed while others fail. Items not in the response dictionary succeeded. # Batch reassign tasks Source: https://docs.reply.io/api-reference/tasks/batch-reassign-tasks /api-reference/bundled.yaml post /v3/tasks/batch/assign _Requires the `tasks:write` scope (or a broader one that includes it)._ Reassigns multiple tasks to a user. The target user must be a member of the caller's team. Non-atomic — some may succeed while others fail. Items not in the response dictionary succeeded. # Bulk delete tasks Source: https://docs.reply.io/api-reference/tasks/bulk-delete-tasks /api-reference/bundled.yaml post /v3/tasks/bulk-delete _Requires the `tasks:write` scope (or a broader one that includes it)._ Deletes multiple tasks by ID. Non-atomic — some may succeed while others fail. Items not in the response dictionary succeeded. # Complete a task Source: https://docs.reply.io/api-reference/tasks/complete-a-task /api-reference/bundled.yaml post /v3/tasks/{id}/complete _Requires the `tasks:operate` scope (or a broader one that includes it)._ Marks a task as completed without execution (no email sent, no SMS sent). For tasks that require execution (sending), use the execute endpoint instead. # Create a task Source: https://docs.reply.io/api-reference/tasks/create-a-task /api-reference/bundled.yaml post /v3/tasks _Requires the `tasks:write` scope (or a broader one that includes it)._ Creates a new task. The template body may contain handlebars variables (e.g. `{{firstName}}`) which are resolved when the task is read or executed. # Delete a task Source: https://docs.reply.io/api-reference/tasks/delete-a-task /api-reference/bundled.yaml delete /v3/tasks/{id} _Requires the `tasks:write` scope (or a broader one that includes it)._ Deletes a single task by ID. Returns 204 on success. # Execute and complete a task Source: https://docs.reply.io/api-reference/tasks/execute-and-complete-a-task /api-reference/bundled.yaml post /v3/tasks/{id}/execute _Requires the `tasks:operate` scope (or a broader one that includes it)._ Executes the task action (sends email or SMS) and completes it. Only ManualEmail (7) and Sms (8) task types support execution. Other task types return 400 — use the complete endpoint for those. # Filter tasks Source: https://docs.reply.io/api-reference/tasks/filter-tasks /api-reference/bundled.yaml post /v3/tasks/filter _Requires the `tasks:read` scope (or a broader one that includes it)._ Returns a filtered, paginated list of tasks. Pagination params (`top`, `skip`) are in query string; filter criteria in request body. All filter fields are optional — an empty body `{}` returns all tasks. The request body must be a valid JSON object; a missing or unparseable body returns 400. # Get a task Source: https://docs.reply.io/api-reference/tasks/get-a-task /api-reference/bundled.yaml get /v3/tasks/{id} _Requires the `tasks:read` scope (or a broader one that includes it)._ Returns full task details by ID. Use `includeContent=true` to also get the rendered content (variables resolved). # List all tasks Source: https://docs.reply.io/api-reference/tasks/list-all-tasks /api-reference/bundled.yaml get /v3/tasks _Requires the `tasks:read` scope (or a broader one that includes it)._ Returns a paginated list of all tasks visible to the current user. For filtered search, use POST /tasks/filter. # Reassign a task Source: https://docs.reply.io/api-reference/tasks/reassign-a-task /api-reference/bundled.yaml put /v3/tasks/{id}/assigned-user _Requires the `tasks:write` scope (or a broader one that includes it)._ Changes the assigned user for a single task. The target user must be a member of the caller's team. # Update a task Source: https://docs.reply.io/api-reference/tasks/update-a-task /api-reference/bundled.yaml put /v3/tasks/{id} _Requires the `tasks:write` scope (or a broader one that includes it)._ Full replacement update of a task. Only tasks with status `New` (0) can be updated. Sequence task type and contact cannot be changed. # Get current user Source: https://docs.reply.io/api-reference/user-account/get-current-user /api-reference/bundled.yaml get /v3/whoami _No scope required — any valid API key can call this endpoint._ Returns the authenticated user's ID, username, and team ID. Useful for verifying credentials and identifying the current user and their team. # List team users Source: https://docs.reply.io/api-reference/user-account/list-team-users /api-reference/bundled.yaml get /v3/whoami/team-users _No scope required — any valid API key can call this endpoint._ Returns all users in the authenticated user's team (workspace), including each user's team ID, team name, user ID, display name, and email address. # Create a webhook subscription Source: https://docs.reply.io/api-reference/webhooks/create-a-webhook-subscription /api-reference/bundled.yaml post /v3/webhooks _Requires the `webhooks:write` scope (or a broader one that includes it)._ Creates a new webhook subscription for the authenticated user. `scope` defaults to `personal` when omitted. `team`-scope subscriptions are accepted only when policy allows: any member may create them for public teams or organization mode; only the team owner may create them for private teams. Attempting to create an `organization`-scope subscription is rejected with `code: webHook.organizationScopeNotImplemented` — the value is reserved for future use. # Delete a webhook subscription Source: https://docs.reply.io/api-reference/webhooks/delete-a-webhook-subscription /api-reference/bundled.yaml delete /v3/webhooks/{id} _Requires the `webhooks:write` scope (or a broader one that includes it)._ Permanently deletes the subscription and its delivery-log payloads. # Disable a webhook subscription Source: https://docs.reply.io/api-reference/webhooks/disable-a-webhook-subscription /api-reference/bundled.yaml post /v3/webhooks/{id}/disable _Requires the `webhooks:operate` scope (or a broader one that includes it)._ Pauses a subscription without deleting it — no events fire until re-enabled. Idempotent: calling on an already-disabled subscription still returns `204`. Use this dedicated endpoint rather than `PUT` to toggle the paused state (`PUT` does not accept the `enabled` flag). # Enable a webhook subscription Source: https://docs.reply.io/api-reference/webhooks/enable-a-webhook-subscription /api-reference/bundled.yaml post /v3/webhooks/{id}/enable _Requires the `webhooks:operate` scope (or a broader one that includes it)._ Resumes a paused subscription. Idempotent — calling on an already-enabled subscription still returns `204`. Use this dedicated endpoint rather than `PUT` to toggle the paused state (`PUT` does not accept the `enabled` flag). When the active-subscriptions limit has been reached, returns `409 Conflict` with `code: webHook.limitReached`. # Get a webhook subscription Source: https://docs.reply.io/api-reference/webhooks/get-a-webhook-subscription /api-reference/bundled.yaml get /v3/webhooks/{id} _Requires the `webhooks:read` scope (or a broader one that includes it)._ Returns a single webhook subscription owned by the authenticated user. # Get webhook delivery logs Source: https://docs.reply.io/api-reference/webhooks/get-webhook-delivery-logs /api-reference/bundled.yaml get /v3/webhooks/{id}/logs _Requires the `webhooks:read` scope (or a broader one that includes it)._ Returns a paginated **failure log** for a single subscription — only failed delivery attempts are recorded here; successful deliveries are not listed. Each log entry captures the triggering event id, HTTP status (or `null` when the request could not be completed) and the UTC timestamp of the attempt. # List supported event types Source: https://docs.reply.io/api-reference/webhooks/list-supported-event-types /api-reference/bundled.yaml get /v3/webhooks/events _Requires the `webhooks:read` scope (or a broader one that includes it)._ Returns the catalog of event type names a subscription may listen to. Use any of these values in the `eventType` field when creating or updating a subscription. # List webhook subscriptions Source: https://docs.reply.io/api-reference/webhooks/list-webhook-subscriptions /api-reference/bundled.yaml get /v3/webhooks _Requires the `webhooks:read` scope (or a broader one that includes it)._ Returns a paginated list of the authenticated user's webhook subscriptions, ordered by descending id. Use `top`/`skip` to page through results and inspect `hasMore` to detect additional pages. # Send a test payload Source: https://docs.reply.io/api-reference/webhooks/send-a-test-payload /api-reference/bundled.yaml post /v3/webhooks/{id}/test _Requires the `webhooks:operate` scope (or a broader one that includes it)._ Triggers a synthetic delivery to the subscription's URL so the integrator can validate wiring. Only enabled subscriptions can be tested. # Update a webhook subscription Source: https://docs.reply.io/api-reference/webhooks/update-a-webhook-subscription /api-reference/bundled.yaml put /v3/webhooks/{id} _Requires the `webhooks:write` scope (or a broader one that includes it)._ Full replacement of the mutable fields of an existing subscription. `organization` scope is rejected with `code: webHook.organizationScopeNotImplemented`. # Using the CLI from agents & scripts Source: https://docs.reply.io/cli/agents The reply CLI's machine contract — JSON output, exit codes, the two error shapes, retries, impersonation headers, and composition patterns. The `reply` CLI is built to be driven by coding agents, shell scripts, and CI. It handles the parts that are tedious to reimplement — browser login, token refresh, the team header, retries — and exposes the whole [v3 API](/api-reference/introduction) through [`reply api`](/cli/overview#raw-api-access). That command is the agent surface today; there are no dedicated resource commands yet. ## The `--json` contract Every command accepts `--json` (compact) and `--pretty` (indented). **Data goes to stdout, status and errors go to stderr** — pipes stay clean: ```bash theme={null} reply api /v3/sequences --json | jq '.data.items[].id' reply auth whoami --json | jq -r '.username' reply team list --json | jq -r '.teams[].team_id' ``` `reply api` always emits JSON, with or without a flag — `{"code": , "data": }`. `--pretty` only changes the indentation. ## Exit codes | Code | Meaning | | ---- | ---------------------------------------------------------------------------------- | | `0` | Success | | `1` | API failure (HTTP `>= 400`) or runtime failure (network, corrupt credential store) | | `2` | Usage error — unknown flag, missing argument, no credential to use | ## The two error shapes **`reply api` never hides an HTTP response.** Any status, including `4xx` and `5xx`, is printed on stdout as `{code, data}`, where `data` is the v3 `problem+json` body verbatim. The exit code is `1` for `>= 400`. Branch on `.code`: ```bash theme={null} out=$(reply api /v3/contacts/999) || true echo "$out" | jq -e '.code == 404' >/dev/null && echo "not found" ``` **Every other command** reports failures as a single machine-readable line on **stderr** when `--json` or `--pretty` is set: ```json theme={null} {"error":{"status":404,"code":"contact.notFound","title":"Not Found","detail":"Contact with ID 999 not found","hint":"Resource not found."}} ``` Branch on `code`, surface `hint` to the user. Every field except `title` is optional. ## Retries and rate limits Handled inside the CLI, on both paths: * `429`, `500`, `502`, `503`, and `504` are retried up to 3 times. * `Retry-After` is honored when present, capped at 30 seconds; otherwise the backoff is exponential from 500 ms. * Network failures are retried on the same schedule, then surface as a runtime error (exit `1`). Don't wrap your own retry loop around write calls — a retried `POST` can double-create. Verify with a follow-up `GET` instead. [Rate limits](/api-reference/rate-limits) documents the API-side windows. ## Teams and impersonation Requests carry the team header from `--team-id` → `REPLY_TEAM_ID` → the profile's pinned team. If a call needs a team and the credential spans several, the API returns `TEAM_REQUIRED` and the CLI adds a one-line fix-it hint on stderr. Pin one non-interactively: ```bash theme={null} reply team use 1045 # persists on the active profile reply --team-id 1045 api /v3/sequences # or scope a single call ``` With an [organization API key](/api-reference/authentication#special-api-keys), name the acting user with `--user-id ` or `--user-email ` (which also needs a team id). Pass exactly one. These are **flag-only** — never read from the environment, never written to disk — so an agent must supply them per invocation: ```bash theme={null} reply --api-key "$ORG_KEY" --user-id 12345 api /v3/whoami reply --api-key "$ORG_KEY" --team-id 1045 --user-email rep@acme.com api /v3/sequences ``` Rejection codes for organization keys are listed under [Rejection responses](/api-reference/authentication#rejection-responses). ## Safety is the caller's job The CLI has **no `--dry-run` and no confirmation gates**. `reply api` sends exactly the request you give it — a `DELETE` deletes, and a `POST /v3/sequences/{id}/start` begins real outreach. The only interactive prompt in the whole CLI is `reply profile delete`, which `-y` skips. An agent driving `reply api` owns the guardrails the [platform safety rules](/agents/safety) describe: confirm high-stakes actions with the user first, echo the exact request you're about to send, and prefer a read-back over a retry. Two habits that help: * Resolve ids with a `GET` before mutating; never invent numeric ids. * Use `--verbose` while developing a call — it prints the full request and response to stderr with credentials redacted, leaving stdout pipeable. ## Non-interactive environments CI and agent sandboxes have no browser, so `reply auth login` won't work. Supply a key instead: ```bash theme={null} export REPLY_API_KEY="$REPLY_KEY" # or pass --api-key per call reply auth whoami --json # verify before doing work ``` Add `-q/--quiet` to silence progress messages on stderr; warnings and errors are still printed. `REPLY_CONFIG_DIR` relocates the credential store when the default home directory isn't writable. ## Composition patterns ```bash theme={null} # every active sequence's id and name, as TSV reply api '/v3/sequences?status=active' --json \ | jq -r '.data.items[] | [.id, .name] | @tsv' # pause every active sequence whose reply rate was under 1% last week reply api /v3/sequences/stats --body '{"filters":{"dateRangePreset":"lastWeek"}}' --json \ | jq -r '.data[] | select(.status == "active" and .emailOverview.repliedPercentage < 1) | .sequenceId' \ | xargs -I{} reply api /v3/sequences/{}/pause --method POST # fail a CI job when the credential no longer works reply auth whoami --json >/dev/null || exit 1 ``` The CLI composes with cron for scheduled jobs, `jq` for filtering, and the [Agent Skill](/skills/overview) for procedure — the skill supplies the workflow, the CLI executes it. ## Drop-in prompt A ready-to-paste system prompt encoding this contract lives at [Drop-in system prompts → CLI variant](/agents/prompts#cli-variant). # Reply CLI Source: https://docs.reply.io/cli/overview The Reply.io command line — sign in once, then run any v3 API call as yourself from your terminal, your scripts, or CI. [`reply`](https://www.npmjs.com/package/reply-cli) is the official command-line interface for Reply.io. Sign in once and every request runs as you. Today it covers **authentication and identity**, and [`reply api`](#raw-api-access) gives you authenticated access to the full [v3 API](/api-reference/introduction) — no HTTP client, no header wrangling. Higher-level commands for sequences, contacts, and the inbox are on the way. | | | | ----------- | -------------------------------------------------------------------------- | | **Package** | [`reply-cli`](https://www.npmjs.com/package/reply-cli) (npm) | | **Command** | `reply` | | **Runtime** | Node.js 20 or newer | | **Auth** | OAuth browser login, or an API key | | **Output** | Human-readable by default; `--json` / `--pretty` for machines | | **Source** | [github.com/reply-team/reply-cli](https://github.com/reply-team/reply-cli) | | **Status** | Pre-1.0 — see [Versioning](#versioning) | ## Install ```bash theme={null} npm install -g reply-cli # installs the `reply` command (Node 20+) reply --version ``` Or run it without installing: ```bash theme={null} npx -y reply-cli auth login ``` ## Authenticate Log in through your browser — no key to copy, no key to rotate: ```bash theme={null} reply auth login ``` Prefer an API key? Read it from stdin so it never lands in your shell history: ```bash theme={null} reply auth login --with-token ``` Keys come from Reply → **Settings → API Keys**; scopes and key types are covered in [Authentication](/api-reference/authentication). Inspect and manage the active credential: ```bash theme={null} reply auth status # who you're signed in as, and how — no secrets shown reply auth whoami # validate the stored credential against the API reply auth logout # remove the stored credential ``` ### Credential precedence Resolved in strict order, first hit wins: 1. `--api-key ` flag 2. `REPLY_API_KEY` environment variable 3. the stored credential from `reply auth login` The flag and the environment variable are used for that one invocation and are never written to disk. There is no `.env` file lookup — export `REPLY_API_KEY` yourself, or store a credential with `reply auth login`. ### Where credentials live Credentials are stored as JSON in `~/.config/reply` (`%APPDATA%\reply` on Windows), written `0600` inside a `0700` directory — the same plaintext-file model as `gh`, `aws`, and `az`. OAuth tokens refresh automatically; if a refresh fails the record is cleared and you're asked to log in again. Tokens and keys are redacted in every command's output, `--verbose` included. ## Profiles — more than one Reply.io user A profile is a signed-in account. Profiles let you keep several Reply.io users authenticated at once and switch between them, each with its own stored credential. Most people never need one: the default profile is used until you create another. Name them however you like — account emails work well: ```bash theme={null} reply profile add alice@reply.io reply profile use alice@reply.io # make it the active profile reply auth login # signs in alice@reply.io reply profile list # '*' marks the active profile reply --profile bob@reply.io auth whoami # override for a single command ``` The active profile resolves as `--profile` → `REPLY_PROFILE` → the profile set with `profile use` → the built-in default. Manage them after creation: ```bash theme={null} reply profile show # the active profile — team, auth method, no secrets reply profile show alice@reply.io # a specific one reply profile rename alice@reply.io ally # also moves the stored credential reply profile delete ally # removes it and its stored credential ``` ## Teams A profile can pin a team (workspace). The pinned team is sent as the `X-TEAM-ID` header, with precedence `--team-id` → `REPLY_TEAM_ID` → the profile's team. The `team` command reads and writes the **active profile's** team: ```bash theme={null} reply team list # teams you can act in ('*' marks the profile's team) reply team current # the pinned team, plus the effective team from whoami reply team use 1045 # verify 1045 is one of your teams, then pin it reply team clear # remove the pin ``` If a call needs a team and you belong to more than one, the API answers with a `TEAM_REQUIRED` error listing your teams — run `reply team use ` to pin one, or pass `--team-id ` for a single command. ## Raw API access `reply api` is a raw, authenticated passthrough to any v3 endpoint — the escape hatch for everything the CLI has no dedicated command for yet. Use the path exactly as it appears in the [API reference](/api-reference/introduction), starting with `/v3`; the query string goes in the path. A `--body` switches the method to `POST` (override with `--method`), and it accepts inline JSON, `@file`, or `-` for stdin. ```bash theme={null} reply api /v3/whoami # your identity + team reply api /v3/sequences # list sequences reply api /v3/contacts --pretty # list contacts, indented reply api /v3/sequences/12345 # one sequence by id reply api /v3/contacts --body @contact.json # create a contact (POST) echo '' | reply api /v3/contacts --body - # body from stdin reply api /v3/whoami --verbose # full request/response on stderr ``` It prints `{ "code": , "data": }` and exits non-zero on HTTP `>= 400`. See [Using the CLI from agents & scripts](/cli/agents) for the full machine contract. ## Command reference Run `reply --help` for the exact flags of any command — the installed help always matches your version. ### `reply auth` | Command | Description | | ------------------------------- | ---------------------------------------------------------------------- | | `reply auth login` | Log in via OAuth in the browser | | `reply auth login --with-token` | Store an API key read from stdin | | `reply auth status` | Active credential source, method, user, and OAuth expiry — no secrets | | `reply auth whoami` | Validate the active credential against the API and print the principal | | `reply auth logout` | Remove the stored credential | ### `reply profile` | Command | Description | | ----------------------------------------- | -------------------------------------------------------------------- | | `reply profile add ` | Create a profile (`--team-id` optionally pins a team) | | `reply profile use ` | Make it the active profile, used until changed | | `reply profile list` | List profiles; `*` marks the active one | | `reply profile current` | Print the active profile name | | `reply profile show [name]` | Show a profile's team and authorization — no secrets | | `reply profile set --team-id ` | Pin a team on a profile | | `reply profile unset team-id` | Clear the pinned team | | `reply profile rename ` | Rename a profile and move its stored credential | | `reply profile delete ` | Delete a profile and its stored credential (`-y` to skip the prompt) | ### `reply team` | Command | Description | | --------------------- | ------------------------------------------------------- | | `reply team list` | Teams you can act in | | `reply team current` | The active profile's pinned team and the effective team | | `reply team use ` | Pin a team (verified against your teams) | | `reply team clear` | Remove the pin | ### `reply api` | Command | Description | | ------------------------------------------ | ----------------------------------------------------------------- | | `reply api ` | Raw authenticated request to a v3 endpoint; prints `{code, data}` | | `reply api --body ` | Send a body (switches the method to `POST`) | | `reply api --method ` | Override the HTTP method | ### Global flags | Flag | Effect | | ---------------------- | -------------------------------------------------------------------------------------------------- | | `-k, --api-key ` | Use this key for one invocation; overrides the env var and stored credential | | `-p, --profile ` | Run as this profile for one invocation | | `--team-id ` | Team/workspace to act in, sent as `X-TEAM-ID` | | `--user-id ` | Act as this user id — [organization API keys](/api-reference/authentication#special-api-keys) only | | `--user-email ` | Act as this user email — organization keys only; requires a team id | | `--json` | Compact JSON on stdout | | `--pretty` | Indented JSON on stdout | | `--verbose` | Full request/response on stderr, credentials redacted | | `-q, --quiet` | Suppress progress messages on stderr; warnings and errors still shown | | `-v, --version` | Print the CLI version | ### Environment variables | Variable | Description | | ------------------ | -------------------------------------------------------------------------- | | `REPLY_API_KEY` | API key used as the credential for the current invocation | | `REPLY_PROFILE` | Profile to use (same as `--profile`) | | `REPLY_TEAM_ID` | Team/workspace id sent as `X-TEAM-ID` (same as `--team-id`) | | `REPLY_CONFIG_DIR` | Config directory (default `~/.config/reply`; `%APPDATA%\reply` on Windows) | ## Why a CLI when there's REST and MCP? * **Authentication is the hard part, and it's solved here.** Browser login, token refresh, multiple accounts, and the team header are handled for you — `reply api` is a `curl` that is already authenticated as the right user in the right workspace. * **Coding agents are exceptionally good at shell commands.** They get composability — pipes, `jq`, cron — without writing an HTTP client. See [Using the CLI from agents](/cli/agents). * **Scriptable one-offs.** Terminal and CI access to the API for work that doesn't warrant a real integration. ## What isn't in the CLI yet There are no dedicated commands for sequences, contacts, the inbox, or reporting yet — reach them through `reply api` today, or use the interface that fits: | Need | Where today | | ------------------------------ | --------------------------------------- | | Any v3 endpoint, authenticated | `reply api /v3/…` | | A tool surface for LLM agents | [Reply MCP](/mcp/overview) | | Your own integration | [REST API](/api-reference/introduction) | | Event-driven automation | [Webhooks](/webhook-events) | ## Versioning `reply-cli` follows [semantic versioning](https://semver.org), with versions derived from Conventional Commits. **Pre-1.0.** While the version is `0.x` the CLI is still stabilizing, so — per semver's 0.x rule — a minor release (`0.x.0`) may contain breaking changes. Pin an exact version if you need stability before `1.0.0`. From `1.0.0` onward, a major bump is required to remove or rename a command, flag, or argument; change the meaning of an exit code; change the `--json` / `--pretty` output shape; change the config format or a `REPLY_*` environment variable; or raise the minimum Node.js version. New commands, new optional flags, and new fields in `--json` output are additive and ship in minor releases. ## Links * Package: [npmjs.com/package/reply-cli](https://www.npmjs.com/package/reply-cli) * Source and issues: [github.com/reply-team/reply-cli](https://github.com/reply-team/reply-cli) * Next: [Using the CLI from agents & scripts](/cli/agents) # Decide what to scale or fix Source: https://docs.reply.io/guides/analyze-performance Turn raw reporting data into decisions — what to scale, pause, or rewrite. **Outcome:** a performance readout (delivered, opens, replies, interested, meetings) with a diagnosis and one or two recommended actions. ## Best interface **CLI for reporting agents** — [`reply api`](/cli/overview#raw-api-access) with `--json` makes the reporting endpoints pipeable and cron-able. **MCP for Q\&A-style analysis** — "compare Q3 sequences" resolves to `reply_compare_sequence_performance` in one call. ## Steps Both endpoints take a `filters` object; `dateRangePreset` accepts `lastWeek`, `lastMonth`, `lastYear`, or `allTime`. ```bash theme={null} reply api /v3/reporting/emails/overview \ --body '{"filters":{"dateRangePreset":"lastWeek"}}' --json reply api /v3/sequences/stats \ --body '{"filters":{"dateRangePreset":"lastWeek"}}' --json ``` ```bash theme={null} reply api /v3/sequences/12345/stats \ --body '{"filters":{"dateRangePreset":"lastMonth"}}' --json ``` MCP: `reply_get_sequence_stats` (one sequence, custom date window) or `reply_compare_sequence_performance` (up to 25 side by side — align by SequenceId, treat missing rows as no data). Benchmark deliverability (bounces), copy (opens vs replies), and targeting (replies vs interested). Flag stalled or degraded sequences. The [analyze-performance skill](/skills/catalog#analyze-performance) packages this diagnosis. Pausing sequences or editing copy are production changes: recommend, confirm, then execute ([Manage sequences](/guides/improve-sequences) has the loop). ## Availability notes * Reports, per-sequence stats, and comparisons: **available today**. * Stats endpoints can throttle earlier than CRUD endpoints — budget calls accordingly ([Rate limits](/api-reference/rate-limits)). * Meetings are booked via Reply's in-app scheduler; the API **reports** them (meetings ledger) but can't book them. ## Related * [Improve sequences every cycle](/guides/improve-sequences) — acting on the diagnosis * [Skill: Analyze performance](/skills/catalog#analyze-performance) # Automate outbound end-to-end Source: https://docs.reply.io/guides/automate-outbound Event-driven and scheduled automation — webhooks for real-time reactions, CLI + cron for recurring hygiene. **Outcome:** workflows that run without anyone asking — inbound leads answered in minutes, lists that stay clean, dormant contacts revived on a schedule. ## Best interface **API + webhooks** — event-driven automation is REST-only: subscribe once, react in real time. **CLI + cron** — scheduled jobs like a weekly hygiene sweep are a natural fit for [`--json` composition](/cli/agents#composition-patterns). ## Pattern 1: Event-driven (inbound lead follow-up) Speed-to-lead is most of the conversion rate. This loop is event-driven end to end — no polling: A [webhook event](/webhook-events) (or your product's own signup/demo-request event) tells the agent a lead arrived. Payload shapes: [Webhook event payloads](/webhook-event-payloads). Create/update the contact with source context in custom fields ([Create contacts](/guides/import-contacts)); score against your ICP. Auto-enrichment of the lead is **coming soon** (Enrichment API). Hot leads → short, direct sequence; colder → nurture. Add the contact and start ([Launch outreach](/guides/launch-outreach)). For an immediate one-off first response outside a sequence, use the outreach-action endpoints ([API Reference](/api-reference/introduction)). Watch reply categories and meeting intent ([Process replies](/guides/convert-replies-to-meetings)); meetings and activity land in reporting automatically. ## Pattern 2: Scheduled (list hygiene + re-engagement) Deliverability is a compounding asset. A weekly cron sweep keeps the base clean, then re-engages what survives: ```bash theme={null} reply api '/v3/contacts/filter?top=1000' \ --body '{"rules":[{"property":"","condition":"","value":""}]}' --json ``` Filter by last activity, bounce history, or missing fields. The available `property` and `condition` names are listed with the Filter contacts endpoint in the [API Reference](/api-reference/introduction); page with `top` and `skip` until `hasMore` is `false`. Schedule email validation across the segment; add bounced domains, opt-outs, and competitor domains to blacklist rules (Suppression & Blacklist API — see [API Reference](/api-reference/introduction)). Bulk-update or remove dead records; move survivors into clean lists. Run a light-touch sequence (2–3 low-pressure touches) against contacts that finished without converting. Load reengagement cards into a Jason knowledge base for a fresh angle ([Build an AI SDR](/guides/build-an-ai-sdr)). Re-enrichment before re-engagement ("did they change jobs?") is **coming soon**. Compare bounce and reply rates before/after with `POST /v3/reporting/emails/overview` (its `compareTo` field returns the trend against a previous period); track the revival rate to decide if the sweep becomes quarterly. ## Availability notes * Webhooks, contact CRUD, validation, suppression, sequences, and reporting: **available today**. * Enrichment-dependent steps (lead auto-enrichment, dormant-refresh): **coming soon**. ## Related * [Webhook events catalog](/webhook-events) · [Payloads](/webhook-event-payloads) * [Using the CLI from agents & scripts](/cli/agents) * [Convert replies into meetings](/guides/convert-replies-to-meetings) · [Build a supervised AI SDR](/guides/build-an-ai-sdr) # Build a supervised AI SDR Source: https://docs.reply.io/guides/build-an-ai-sdr Give Jason a goal, knowledge, and guardrails — then supervise through approval gates instead of operating by hand. **Outcome:** a supervised, self-improving outbound system — Jason (Reply's AI SDR) writes and sends outreach and handles replies, while your agent supervises through approval queues and performance data. The highest-altitude pattern: an agent configuring an agent. ## Best interface **MCP** — the Jason toolset is richest there: 31 of the 70 tools drive knowledge bases, offers, playbooks, reply handlers, reengagement cards, and the approval queue. The REST API covers the knowledge/offer/playbook layer. ## Steps Translate the objective into an offer, a target market, and success metrics. Draft offer content from a website with MCP `reply_generate_offer_from_website` (review, then `reply_create_offer`). `reply_create_knowledge_base` → add URL sources (`reply_add_knowledge_base_source`), reply handlers (how Jason answers pricing/security/… questions), and reengagement cards (win-back plays). See [MCP tools → Jason AI SDR](/mcp/tools#jason-ai-sdr). The offer says *what's being sold and to whom*; the playbook says *how* (tone, structure, channels). `reply_create_offer`, `reply_create_playbook`, then attach both to the sequence. Enroll contacts you already have ([Launch outreach](/guides/launch-outreach)). Intent-signal targeting and Live Data sourcing are **coming soon** — see [Find prospects](/guides/find-ideal-prospects). `reply_set_sequence_reply_mode` → **Review** (Jason drafts, you approve) is the safe default. **Autonomous** (Jason sends without approval) is a [high-stakes switch](/agents/safety) — verify offer/playbook/knowledge base first and confirm explicitly. Recipe: [Switch Jason to Autonomous](/mcp/recipes#switch-jason-to-autonomous). `reply_list_pending_approvals` → approve (sends immediately), regenerate with feedback, or reject (removes the contact from the sequence — irreversible). Recipe: [Supervise Jason in Review mode](/mcp/recipes#supervise-jason-in-review-mode). Replies flow into the unified inbox with AI categorization; escalate high-intent threads to a human. Read the meetings ledger and per-sequence stats; refine the offer, playbook, and targeting based on what converts ([Analyze performance](/guides/analyze-performance)). ## Availability notes * Knowledge bases, reply handlers, reengagement cards, offers, playbooks, reply-mode control, and the approval queue: **available today via MCP** (and the AI SDR REST module). * **Coming soon:** intent-signal prospect targeting; full autopilot enrollment loops. Everything labeled available above is callable now. ## Related * [MCP recipes: Supervise Jason / Switch to Autonomous](/mcp/recipes#supervise-jason-in-review-mode) * [Convert replies into meetings](/guides/convert-replies-to-meetings) — the human-approved counterpart * [Agent safety rules](/agents/safety) — why Autonomous is gated # Convert replies into meetings Source: https://docs.reply.io/guides/convert-replies-to-meetings Triage the inbox, surface interested prospects, and send approved replies — event-driven or conversational. **Outcome:** every reply triaged, interested prospects surfaced, responses sent with explicit approval — from both email and LinkedIn, in one inbox. ## Best interface **The [`manage-replies` skill](/skills/catalog#manage-replies)** for approved, gated sending. **Webhooks for real-time** — subscribe to [`email_replied` and `reply_categorized` events](/webhook-events) instead of polling. **MCP** for conversational triage in a client. ## Steps Real-time: subscribe to [webhook events](/webhook-events) — `email_replied`, `reply_categorized` — pushed to your endpoint (see [payloads](/webhook-event-payloads)). Polling: `reply api /v3/inbox/threads/filter --body '{"source":"unread"}'` or MCP `reply_get_inbox_emails`. Group threads by category and meeting intent. LinkedIn and email replies land in the same unified inbox with the same categories. ```bash theme={null} reply api /v3/inbox/threads/categories --json # resolve category ids first reply api /v3/inbox/threads/filter \ --body '{"categoryIds":[7],"onlyWithMeetingIntent":true}' --json ``` ```bash theme={null} reply api /v3/inbox/threads/58217 --json reply api /v3/inbox/threads/58217/messages --json ``` Sending reaches a real prospect — a [high-stakes action](/agents/safety). Nothing here prompts for confirmation, so show the exact text, get approval, then send. The body's `channel` must match the thread's, or the call is rejected with `inboxThread.channelMismatch`. ```bash theme={null} reply api /v3/inbox/threads/58217/messages \ --body '{"channel":"email","message":"Thanks — does Tuesday at 10am work?","applySignature":true}' --json ``` MCP: `reply_send_inbox_reply` (channel must match the thread; body only in v1 — no Cc/Bcc, attachments, or scheduling). See the [MCP recipe](/mcp/recipes#reply-to-an-inbox-thread). ```bash theme={null} reply api /v3/inbox/threads/58217/category --method PUT --body '{"categoryId":42}' --json ``` Route meeting-intent threads to scheduling; mark contacts as replied to stop further automated outreach (MCP: `reply_mark_contacts_as_replied`). ## Availability notes * Inbox triage, replying, categorization, and webhooks: **available today**. * **Fully automated reply policies (auto-answer) are not in Skill v1** — every send is human-approved. For AI-drafted replies with an approval queue, see [Build an AI SDR](/guides/build-an-ai-sdr). ## Related * [Build a supervised AI SDR](/guides/build-an-ai-sdr) — Jason drafts the replies, you approve * [Automate outbound end-to-end](/guides/automate-outbound) — the event-driven pattern in full * [Webhook events catalog](/webhook-events) # Find your ideal prospects Source: https://docs.reply.io/guides/find-ideal-prospects From an ICP definition to a saved, deduplicated prospect list — what works today and what's coming. **Outcome:** a contact list of prospects matching your ideal customer profile, ready for outreach. The end-to-end path — searching Reply's 1B+ B2B database from an ICP — depends on the **Live Data / prospect-search API, which is not generally available yet**. The same applies to waterfall enrichment. This guide describes what works today and labels the rest honestly. ## Best interface today **Bring your own list.** Until prospect search ships, source prospects externally and enter the platform at the import step — [Create and import contacts](/guides/import-contacts) covers the fully-available path (bulk import with dedupe via the API or Skills). ## Steps Turn the goal into concrete filters: job titles, seniority, department, industry, company size, location. An agent can derive this from your best customers' domains and reporting data. Live Data search over the 1B+ contact database with result preview before committing credits. Ships as an API module, a `reply` CLI command, and the `find-prospects` + `build-icp` [skills](/skills/catalog#coming-soon). Import selected prospects as contact records organized into a named list — today via CSV: [Create and import contacts](/guides/import-contacts). Waterfall enrichment (emails, phones, firmographics) depends on the Enrichment API. Until then, source enrichment externally before import. Schedule email validation on the list to protect deliverability — part of [Automate workflows](/guides/automate-outbound). ## Availability notes * Prospect search & enrichment: **coming soon** — tracked on the [skill catalog](/skills/catalog#coming-soon); they'll appear as API modules, CLI commands, and skill workflows when the endpoints ship. * Everything downstream of a list you already have is fully available today. ## Related * [Import and clean contacts](/guides/import-contacts) — the available entry point * [Launch multichannel outreach](/guides/launch-outreach) — the next step once the list exists # Import and clean contacts Source: https://docs.reply.io/guides/import-contacts CSV in, deduplicated contacts out — mapped, verified, and organized into a list ready for outreach. **Outcome:** clean contact records in your workspace, deduplicated, validated, and organized into a list ready for sequencing. ## Best interface **API for bulk import** — one `POST /v3/contacts/import` call handles dedupe, list assignment, and per-item outcomes. Drive it from your own code, or from the terminal with [`reply api`](/cli/overview#raw-api-access). **MCP** for conversational, one-at-a-time creation. ## Steps Import takes JSON, not CSV — convert your spreadsheet first. The body is `{"items": [...], "options": {...}}`, where each item uses the contact fields and `options` controls dedupe and list assignment. **Maximum 1000 items per request** — batch anything larger. ```json theme={null} { "items": [ {"email": "john@acme.com", "firstName": "John", "lastName": "Doe", "company": "Acme"} ], "options": {"skipExisting": true, "listIds": [42]} } ``` ```bash theme={null} reply api /v3/contacts/import --body @import.json --json ``` The response reports added / updated / skipped / failed counts with a per-item outcome — report exact numbers rather than "done". Nothing is written until you send this call, so validate the payload locally first: there is no server-side dry-run. For one-at-a-time or system-to-system sync, use the Contacts endpoints in the [API Reference](/api-reference/introduction), or `reply_create_contact` / `reply_update_contact` via [MCP](/mcp/tools#contacts) (needs a name plus email or LinkedIn URL). Schedule email validation on the list — never send to a dead address. Available today via the API; part of the [list-hygiene loop](/guides/automate-outbound). ```bash theme={null} reply api /v3/contact-lists/42 --json reply api '/v3/contacts/filter?top=100' --body '{"listId":42}' --json | jq '.data.items | length' ``` ## Availability notes * CSV import, contact CRUD, lists, and email validation: **available today**. * Waterfall **enrichment** of imported records (fill missing emails/phones/firmographics): **coming soon** — see [Find prospects](/guides/find-ideal-prospects#availability-notes). ## Related * [Launch multichannel outreach](/guides/launch-outreach) — enroll the list into a sequence * [Automate outbound end-to-end](/guides/automate-outbound) — keep the list clean on a schedule * [Skill: Import prospects](/skills/catalog#import-prospects) # Improve sequences every cycle Source: https://docs.reply.io/guides/improve-sequences Operate running sequences — A/B variants, per-step stats, pausing losers, promoting winners. **Outcome:** sequences that measurably improve every cycle — data-picked copy on every step, losers paused, winners promoted to templates. ## Best interface **CLI for ops loops** — [`reply api`](/cli/overview#raw-api-access) against the stats and lifecycle endpoints composes with `jq` and cron for continuous optimization. **MCP interactively** — inspect steps and variants, compare sequences, pause/start conversationally. ## Steps Openers and first follow-ups move the numbers hardest. Add message variants via the Sequences API (see [API Reference](/api-reference/introduction)); inspect existing ones via MCP: `reply_get_sequence_steps` → `reply_get_sequence_step_variants`. Run the sequence; the platform distributes contacts across enabled variants automatically. ```bash theme={null} reply api /v3/sequences/12345/stats \ --body '{"filters":{"dateRangePreset":"lastMonth"}}' --json ``` MCP: `reply_get_sequence_stats` for one, `reply_compare_sequence_performance` for up to 25 side by side. ```bash theme={null} reply api /v3/sequences/stats --body '{"filters":{"dateRangePreset":"lastMonth"}}' --json \ | jq -r '.data[] | select(.status == "active" and .emailOverview.repliedPercentage < 1) | .sequenceId' \ | xargs -I{} reply api /v3/sequences/{}/pause --method POST ``` The list endpoint accepts only `lastWeek` or `lastMonth`. Disable underperforming variants mid-flight via the API; pause whole sequences as above or via MCP. Save winning messages as email templates so every future sequence starts from proven copy — Templates via the [API](/api-reference/introduction). Confirm the aggregate effect over time with `POST /v3/reporting/emails/overview`, or the [analyze-performance skill](/skills/catalog#analyze-performance). ## Availability notes * Everything here is **available today**. Per-contact status changes inside a sequence (pause one person, mark finished) are richest via MCP: `reply_change_status_in_sequence`. ## Related * [Decide what to scale or fix](/guides/analyze-performance) — the diagnosis layer * [Launch multichannel outreach](/guides/launch-outreach) — starting new sequences # Launch multichannel outreach Source: https://docs.reply.io/guides/launch-outreach From a contact list to a running multichannel sequence — accounts checked, contacts enrolled, start confirmed. **Outcome:** a running sequence with assigned mailboxes, a schedule, and enrolled contacts — started only after explicit confirmation. ## Best interface **The [`launch-outreach` skill](/skills/catalog#launch-outreach)** runs the whole checklist and gates the start on your explicit confirmation. **In an MCP client**, follow the [Launch a sequence safely recipe](/mcp/recipes#launch-a-sequence-safely) — same checklist as MCP tool calls. ## Steps Email steps need a connected mailbox; LinkedIn steps need a linked LinkedIn account. API: `GET /v3/email-accounts`, `GET /v3/linkedin-accounts` (`reply api /v3/email-accounts`). MCP: `reply_list_email_accounts`, `reply_list_linkedin_accounts`. API: `POST /v3/sequences` to create, `GET /v3/sequences` to pick an existing one. MCP: `reply_search_sequences`. For LinkedIn-first cadences, lead with LinkedIn steps and fall back to email for prospects who don't accept. MCP: `reply_assign_email_account_to_sequence`, `reply_assign_schedule_to_sequence` — a sequence without a mailbox fails to start with `NoEmailAccounts`. Add contacts by id, in bulk. Resolve the ids first — never guess them. ```bash theme={null} reply api /v3/sequences/12345/contact-links/bulk \ --body '{"contactIds":[101,102],"removeFromExisting":false}' --json ``` Per-contact skips (already in sequence, blacklisted) are reported, not failures — read them and report exact counts. Starting begins real outreach — a [high-stakes action](/agents/safety) on every surface. Nothing below asks for confirmation, so ask the user yourself before you run it. ```bash theme={null} reply api /v3/sequences/12345/start --method POST --json ``` MCP: confirm with the user, then `reply_start_sequence`. API: `reply api /v3/sequences/12345 --json` · MCP: `reply_get_sequence_stats` or `reply_search_sequences` to confirm the status is Active. ## Availability notes * Everything in this guide is **available today**, including LinkedIn steps (with a linked LinkedIn account). * Complex step editing (A/B variants on live sequences, LinkedIn step authoring) is handed off to the Reply app in Skill v1. ## Related * [Improve sequences every cycle](/guides/improve-sequences) — optimize what's now running * [Convert replies into meetings](/guides/convert-replies-to-meetings) — handle the responses * [MCP recipe: Launch a sequence safely](/mcp/recipes#launch-a-sequence-safely) # Building agents Source: https://docs.reply.io/mcp/agent-guide Design principles, high-stakes gating, and a drop-in system prompt for agents that use Reply MCP. Reply MCP executes a successful call **immediately** — there is no undo. These principles keep an agent safe and effective. They pair with the [tool contract](/mcp/tool-contract) (how calls behave) and the [workflow recipes](/mcp/recipes) (concrete call graphs). For the platform-wide, surface-independent versions of these rules, see [Agent safety rules](/agents/safety) and [Drop-in system prompts](/agents/prompts). ## Design principles ### Resolve before you mutate Almost every mutating tool takes exact numeric IDs (sequence, contact, task, thread, user, email-account, LinkedIn-account, schedule, offer, playbook, knowledge-base). **Never invent an ID, and never ask the user for one** — users don't know internal IDs. Search → confirm the match → act → verify: ```text theme={null} User: "Add John from Acme to the Q3 outbound sequence." 1. reply_search_contacts(email or LinkedIn URL) — this tool needs an email/LinkedIn, not a name; if you only have a name, ask the user for an email first. 2. reply_search_sequences(name: "Q3 outbound") 3. If exactly one contact and one sequence match, confirm and call reply_add_contact_to_sequence(sequenceId, [contactId]). 4. Read NotProcessed in the result; verify with reply_get_contact_activity(contactId). ``` ### Gate high-stakes actions Confirm with the user before anything that sends to a prospect, starts outreach, enrolls contacts, changes ownership, blacklists, bulk-approves, or switches Jason to Autonomous. Two traps worth naming: * **`reply_reject_message` doesn't just discard a draft** — it removes the contact from the sequence entirely. To merely revise a draft, use `reply_regenerate_message`. * **`reply_send_inbox_reply` supports only `threadId` + `channel` + `message` in v1** — no Cc/Bcc, attachments, or scheduling; 32,000-char max; the channel must match the thread's. ### Separate discovery, configuration, and execution Discover objects and IDs (`search_*` / `list_*` / `get_*`), configure the sequence (mailboxes, schedules, offers, knowledge bases, playbooks, reply mode), then execute (start, approve, send, complete). `reply_start_sequence` fails with `NoEmailAccounts` or `NoContacts` if you skip configuration. ### MCP is the interactive surface; REST is the exhaustive one These 70 tools cover most day-to-day operations. Drop to the [REST API](/api-reference/introduction) (`api.reply.io/v3`) for bulk imports and updates, background jobs, deep report exports, and anything absent from `tools/list`. ## High-stakes tools Each of these reaches a prospect or changes ownership/state the instant it succeeds. Require explicit confirmation in almost any agent UX: | Tool | Why it's high-stakes | | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `reply_start_sequence` | Begins outreach processing | | `reply_add_contact_to_sequence` | Enrolls people into outreach | | `reply_send_inbox_reply` | Sends a real message to a contact | | `reply_approve_message` / `reply_bulk_approve_messages` | Send Jason's drafts (bulk is atomic, ≤100) | | `reply_reject_message` | **Irreversible** — discards the draft AND removes the contact from the sequence. Use `reply_regenerate_message` if the user merely dislikes the draft | | `reply_blacklist_contact` | Suppresses an email (or, with `blockEntireDomain`, a whole company domain — including future contacts) from all outreach | | `reply_change_contact_owner` | Changes visibility and responsibility; trust only `AffectedContactIds` when reporting what changed | | `reply_set_sequence_reply_mode` → `Autonomous` | Jason sends without per-message review | Usually worth confirming too (production-affecting, but not prospect-visible): `reply_pause_sequence`, `reply_change_status_in_sequence`, the `reply_assign_*` / `reply_attach_*` configuration tools, `reply_complete_task`, and any create/update/delete on knowledge bases, reply handlers, reengagement cards, offers, or playbooks. The server's `destructiveHint` annotation marks all 39 mutations — use it as the machine-readable gate. ## Drop-in system prompt Add this to an agent's system prompt when it has Reply MCP tools: ```text theme={null} You have access to Reply.io MCP tools. For every request: 1. Classify it: read-only, configuration, outreach-changing, or prospect-visible send. The server annotates every tool (readOnlyHint / destructiveHint) — honor them. 2. For any mutation, resolve exact numeric IDs first with search/list/filter tools. Never guess an ID and never ask the user for one. 3. For high-stakes actions (send, approve, reject, start, enroll, blacklist, change owner, go Autonomous), summarize the target and side effect, then ask the user to confirm. Remember: reject_message removes the contact from the sequence — it is not "discard draft". 4. Parse results from result.content[0].text: {"Success":true,"Data":...} or {"Success":false,"ErrorCode":...,"ErrorMessage":...}. Branch on ErrorCode. Read per-item results (NotProcessed / AffectedContactIds) and report exact counts. 5. Do not pass unknown arguments (schemas are additionalProperties:false) and never send empty strings/arrays for required fields. 6. Paginate with top/skip until HasMore is false. 7. On failure, follow the tool's own failure-mode guidance. Do not blindly retry sends, approvals, starts, or enrollments — a timeout may already have succeeded; verify first. 8. If no tool fits, try reply_get_app_map and reply_search_knowledge_base before saying you can't; then reply_report_unsupported_request if it is truly missing. ``` Next: [workflow recipes](/mcp/recipes) turn these principles into concrete call graphs. # Connect Source: https://docs.reply.io/mcp/connect Add Reply MCP to Claude, Cursor, or any MCP-compatible client. Connect Reply MCP to your AI client in two steps: get your API key, then point your client at `https://mcp.reply.io/`. ## 1) Get your API key Reply MCP authenticates with your Reply.io **personal API key**. Create or copy one under **Settings → API Key** in the [Reply dashboard](https://run.reply.io). A personal API key is the preferred credential because it's **scoped**: you grant it only the permissions your agent needs, and it can call only the tools those permissions cover. A scope is a permission such as `contacts:read` or `sequences:operate`, grouped by area (contacts, sequences, inbox, tasks, channels, AI SDR), so you can give an agent exactly the reach it needs and nothing more. Set the scopes on the key in **Settings → API Key**; see [Scopes](/api-reference/authentication#scopes) for the full list. The MCP connection URL is `https://mcp.reply.io/`. You can also open it in the app under **Execution → Integrations → Reply MCP Server → Configure**, which is where you set up and configure the MCP connection. Treat your API key like a password. Don't share it in public repositories, screenshots, or chat messages. If it's exposed, generate a new API key in Reply. ## 2) Add it to your client ### Header auth (recommended) Most modern MCP clients support remote Streamable HTTP servers with header auth. Point the client at `https://mcp.reply.io/` and pass your key in the `Authorization` header as a bearer token. ```json theme={null} { "mcpServers": { "reply": { "type": "http", "url": "https://mcp.reply.io/", "headers": { "Authorization": "Bearer YOUR_REPLY_API_KEY" } } } } ``` **Claude Code**, one line: ```bash theme={null} claude mcp add --transport http reply https://mcp.reply.io/ \ --header "Authorization: Bearer YOUR_REPLY_API_KEY" ``` ### OAuth (clients without header auth) Some clients don't let you set an API key or custom headers — typically the **UI / desktop apps** of Claude, ChatGPT, and Codex, where you add a connector by URL only. For those, use OAuth: add Reply MCP as a remote/custom connector with the URL `https://mcp.reply.io/` and authorize when prompted — no key to copy or store. OAuth grants access to the **full tool catalog** — it's equivalent to an API key with **all scopes**, and there's no per-scope control over an OAuth connection. So whenever your client does support header auth, prefer a scoped personal API key (above) to limit what the agent can do. Some OAuth clients don't support Client ID Metadata Documents (CIMD) and fall back to Dynamic Client Registration, which is allow-listed on our side. If your client reports an allow-list or registration error when connecting, let us know in the [community Slack](/slack) and we'll review it. ### Fallback: `mcp-remote` (clients without native remote MCP) If your client only supports local (stdio) MCP servers, bridge to the remote server with the [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) proxy and pass your key in the `Authorization` header: ```json theme={null} { "mcpServers": { "reply": { "command": "npx", "args": [ "-y", "mcp-remote", "https://mcp.reply.io/", "--header", "Authorization: Bearer YOUR_REPLY_API_KEY" ] } } } ``` Passing credentials in the URL (for example `?api_key=...`) is not supported. Always authenticate with the `Authorization` bearer header. ## Handshake Once connected, MCP clients drive the standard flow automatically. If you're building a client by hand: 1. Open an HTTP connection to `https://mcp.reply.io/`. 2. Send a JSON-RPC `initialize` with your protocol version and client info. 3. Send the `notifications/initialized` notification if your client library requires it. 4. Call `tools/list` to discover tools, their JSON schemas, and their annotations. 5. Call `tools/call` with a tool name and an argument object. ```json initialize theme={null} { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "your-client", "version": "1.0.0" } } } ``` No `Mcp-Session-Id` is required — `initialize` and `tools/list` work without a session. ## Authentication details An unauthenticated call returns `401 Unauthorized` with an OAuth challenge header: ```http theme={null} WWW-Authenticate: Bearer resource_metadata="https://mcp.reply.io/.well-known/oauth-protected-resource/" ``` The published protected-resource metadata (`GET /.well-known/oauth-protected-resource/`): ```json theme={null} { "resource": "https://mcp.reply.io", "authorization_servers": ["https://oauth.sandbox.replyapp.io"], "bearer_methods_supported": ["header"], "scopes_supported": ["reply-web-api", "mcp:tools"] } ``` For most agents a scoped personal API key is the recommended path — it gives the finest-grained control over what the agent can do (see [Scopes](/api-reference/authentication#scopes)). The OAuth metadata exists for clients (e.g. Claude custom connectors) that prefer a discovery-based flow; OAuth grants the **full tool catalog** (all scopes), so prefer a scoped personal API key when you want to limit an agent's reach. ### Unsupported keys Reply MCP is a single-user connection, so **act-on-behalf API keys are not supported** — including team-level **Team keys** and **Organization API keys**. These are designed to make requests on behalf of other users, which a single-user connection doesn't provide. Use a personal API key or OAuth instead. ## Rate limits The server enforces an hourly window (\~3000 requests/hour). Every response carries the current budget: ```http theme={null} X-Rate-Limit-Limit: 1h X-Rate-Limit-Remaining: 2997 X-Rate-Limit-Reset: 2026-07-05T00:00:00.0000000Z ``` On `429`, back off until the `X-Rate-Limit-Reset` timestamp before retrying. ## Related * [Reply MCP overview](/mcp/overview) — what the server exposes * [Tool reference](/mcp/tools) — all 70 tools * [Connecting Reply MCP to your AI model (Help Center)](https://support.reply.io/en/articles/12955018-connecting-reply-mcp-to-your-ai-model) # Reply MCP overview Source: https://docs.reply.io/mcp/overview The official, live Reply.io MCP server — 70 tools for sequences, contacts, inbox, tasks, and the Jason AI SDR autopilot. Reply MCP is an official, live, remote [Model Context Protocol](https://modelcontextprotocol.io) server that exposes Reply.io's sales-engagement, inbox, AI SDR (Jason), task, account, and help workflows as **70 tools** for any MCP-compatible client — Claude, Cursor, Make, n8n, and custom agents. Everything in these pages was read off the running server via an authenticated `initialize` + `tools/list` handshake and safe validation probes. Tool names, signatures, enum values, annotations, response envelopes, and error codes come from the live server — not hand-maintained prose. If any other documentation disagrees, trust the server (see [Regenerate this reference](/mcp/tools#regenerate-this-reference)). ## At a glance | | | | ---------------- | -------------------------------------------------------------------------------- | | **Endpoint** | `https://mcp.reply.io/` | | **Transport** | Streamable HTTP (responses are SSE `text/event-stream` frames carrying JSON-RPC) | | **Wire format** | JSON-RPC 2.0 over HTTP | | **MCP protocol** | `2025-06-18` | | **Auth** | `Authorization: Bearer ` | | **Rate limit** | Hourly window, \~3000/hour (`X-Rate-Limit-*` headers on every response) | | **Sessions** | None required — `initialize` and `tools/list` work without an `Mcp-Session-Id` | | **Tools** | 70 — 31 annotated `readOnlyHint`, 39 annotated `destructiveHint` | | **Capabilities** | `tools`, `logging` (no prompts or resources advertised) | Add Reply MCP to Claude, Cursor, or any MCP client in a couple of minutes. The full catalog of all 70 tools, grouped by domain. The rules every tool enforces: schemas, envelopes, error codes, retries. Design principles, high-stakes gating, and a drop-in system prompt. Task-based guides — launch outreach, process replies, build an AI SDR. Not sure MCP is the right surface? Compare MCP, Skills, CLI, and API. ## What's exposed The 70 tools cover the day-to-day Reply.io surface an agent needs: | Domain | Tools | What it does | | ------------------------- | :---: | -------------------------------------------------------------------------------------------------------- | | **Sequences** | 16 | Discover, inspect, start/pause, enroll contacts, and configure mailboxes, schedules, and AI SDR settings | | **Contacts** | 8 | Look up, filter, create, update, reassign, blacklist, and read activity | | **Inbox & conversations** | 3 | List inbox threads, send replies, categorize | | **Jason AI SDR** | 31 | Approvals & autopilot, knowledge bases, reply handlers, reengagement cards, offers, and playbooks | | **Tasks** | 3 | List, create, and complete tasks | | **Workspace resolvers** | 5 | Resolve mailboxes, LinkedIn accounts, schedules, lists, and teammates to their IDs | | **Help & meta** | 4 | Search the Help Center, read articles, map the app, report unsupported requests | See the [tool reference](/mcp/tools) for every tool name, its safety annotation, and a one-line purpose. ## MCP vs the REST API MCP and the [REST API](/api-reference/introduction) are two surfaces over **one product** — same account, same credit system. * **MCP** — the interactive surface. 70 curated, annotated tools for agent actions and natural-language workflows. Best for day-to-day operations. * **REST** (`https://api.reply.io/v3`) — the exhaustive surface. Use it for bulk imports and updates, background jobs, deep report exports, webhooks, and template/schedule/mailbox management not exposed as tools. Browse the full v3 REST API — the exhaustive surface for bulk and background operations. ## FAQ Yes — it's an official, live server at `mcp.reply.io`. These pages were generated from an authenticated `initialize` + `tools/list` handshake against the running server. If the server ever returns a different tool set, the server is newer — trust it, and [regenerate the reference](/mcp/tools#regenerate-this-reference) in seconds. Pass your Reply.io API key as an `Authorization: Bearer` header. A call with no credentials returns `401` with a `WWW-Authenticate` challenge; OAuth protected-resource metadata is also published for clients that prefer a discovery-based flow. See [Connect](/mcp/connect). Every tool is annotated in `tools/list`: 31 are `readOnlyHint: true` and 39 are `destructiveHint: true`. Agents can — and should — gate on these annotations before adding their own confirmation UX for the high-stakes subset. See the [tool contract](/mcp/tool-contract). Responses are SSE frames; read the last `data:` frame. A successful `tools/call` returns the payload as a JSON string in `result.content[0].text`. Tool failures are **not** HTTP errors — they arrive as HTTP 200 with `result.isError = true`. See [response envelopes](/mcp/tool-contract#response-envelopes). Use MCP for interactive, natural-language workflows and everyday operations. Drop to the REST API for bulk imports/updates, background jobs, report exports, and anything absent from `tools/list`. Yes. 31 of the 70 tools drive Jason — the approval queue, knowledge bases, reply handlers, reengagement cards, offers, playbooks, and the Review/Autonomous reply mode. # Workflow recipes Source: https://docs.reply.io/mcp/recipes Concrete Reply MCP call graphs — resolve IDs, configure, confirm high-stakes steps, verify. Concrete call graphs an agent can follow. Each one resolves IDs first, configures where needed, confirms before high-stakes steps, and verifies after. See [Building agents](/mcp/agent-guide) for the principles behind them. ## Launch a sequence safely `reply_search_sequences` by name → resolve the exact `sequenceId` (ask the user if ambiguous). `reply_get_sequence_steps` → see which channels the sequence uses. `reply_list_email_accounts`, then `reply_assign_email_account_to_sequence` if none is attached. `reply_list_linkedin_accounts`, then `reply_assign_linkedin_account_to_sequence`; warn if the account is unhealthy. `reply_list_schedules`, then `reply_assign_schedule_to_sequence` if none is set. `reply_attach_offer_to_sequence` / `reply_attach_playbook_to_sequence` / `reply_attach_knowledge_base_to_sequence`, then `reply_set_sequence_reply_mode`. Confirm with the user ("Start sequence X? This begins outreach to its contacts."), then `reply_start_sequence` — expect `NoContacts` / `NoEmailAccounts` / `Archived` if configuration was skipped. `reply_get_sequence_stats` or `reply_search_sequences` to confirm it is Active. ## Add a contact to a sequence `reply_search_contacts` by email or LinkedIn URL (the tool does not accept names — ask the user for an email if that's all you have). If missing and the user confirms details, `reply_create_contact` (needs a name plus at least one of email/LinkedIn URL). `reply_search_sequences` for the target sequence. Confirm, then `reply_add_contact_to_sequence` (up to 100 IDs; per-contact skips arrive in `NotProcessed`, e.g. `ContactAlreadyInSequence`, `ContactInBlackList`). `reply_get_contact_activity` to verify enrollment. ## Supervise Jason in Review mode `reply_set_sequence_reply_mode` → `Review` (if not already). `reply_list_pending_approvals` — filter by sequence, owner, or channel. Inspect the contact and context, compare against the attached playbook/knowledge base, then: * `reply_approve_message` (optionally overriding body/subject) — **sends immediately**; * `reply_regenerate_message` with specific feedback to revise the draft; * `reply_reject_message` **only** if the contact should leave the sequence entirely — rejection is irreversible and removes them from the sequence. `reply_bulk_approve_messages` only after every draft in the batch was reviewed — the batch is atomic: one stale reference rejects the whole batch and nothing is sent. ## Switch Jason to Autonomous Verify the sequence has an offer, playbook, and knowledge base attached and reviewed. Autonomous mode sends replies **without per-message approval**. Get explicit confirmation. `reply_set_sequence_reply_mode` → `Autonomous`. Keep watching `reply_get_inbox_emails` and `reply_get_sequence_stats`. ## Reply to an inbox thread `reply_get_inbox_emails` (pagination only in v1 — no filters; previews only, not full bodies) → resolve the exact `threadId` and note its channel. Draft the reply and show it to the user for approval. `reply_send_inbox_reply` with the matching channel (`Email` or `LinkedIn`) — v1 supports message body only (max 32,000 chars); no Cc/Bcc, attachments, or scheduling. Expect `ChannelMismatch`, `ContactOptedOut`, or `ThreadSendFailed` as the named failure modes. `reply_change_inbox_category` to reflect the new state. ## Handle an unsupported request Confirm no tool in `tools/list` can do it. `reply_get_app_map` — the action may be a UI-only setting; return the exact in-app link. `reply_search_knowledge_base` + `reply_get_knowledge_base_article` — answer a how-to and cite the source. Only if genuinely missing, `reply_report_unsupported_request` with a stable kebab-case `requestKey` and a `category` from its enum — then tell the user plainly you cannot do it. Offer the [REST API](/api-reference/introduction) if it covers the gap. ## Related guides These recipes power the task-based guides, which add the cross-surface view (CLI, Skills, API): * [Launch multichannel outreach](/guides/launch-outreach) · [Convert replies into meetings](/guides/convert-replies-to-meetings) · [Build a supervised AI SDR](/guides/build-an-ai-sdr) · [Improve sequences every cycle](/guides/improve-sequences) # Tool contract & errors Source: https://docs.reply.io/mcp/tool-contract The rules every Reply MCP tool enforces — schemas, pagination, response envelopes, error codes, and retries. These rules apply to **every one of the 70 tools**, verified against the served JSON schemas and live validation probes. An agent that follows them will rarely hit an avoidable error. ## Contract rules the schemas enforce * **Unknown arguments are invalid.** Every `inputSchema` sets `additionalProperties: false`. Don't pass extra keys "just in case" — the call fails validation. * **Required means non-empty.** Required string and array fields reject `null`, `""`, and `[]` alike. In the server's own words: *"null, empty strings, and empty arrays are not accepted for required fields."* * **Every tool is annotated.** `readOnlyHint: true` (31 tools) or `destructiveHint: true` (39 tools) arrives in `tools/list`. Gate on these before adding your own confirmation UX. * **Pagination is uniform.** List/search tools take `top` (default 20, max 100) and `skip`; responses return `Data.Items` plus `HasMore`. Iterate with `skip += top` until `HasMore` is `false`. * **Patch semantics on updates.** Every `update_*` tool changes only the fields you pass; omitted/null fields keep their current value. A passed list field replaces the whole list. * **IDs come from resolvers.** Mutating tools require exact numeric IDs from prior `search_*` / `list_*` / `filter_*` output. The descriptions repeat one rule verbatim: *"Never invent, estimate, default, or ask the user."* * **Approvals are addressed by pair.** Approve/reject/regenerate identify a Jason draft by `sequenceId` + `contactId` — there is no separate draft/message ID. * **Batches are bounded and explicit.** Bulk tools cap at 100 items. `reply_bulk_approve_messages` is atomic (any stale reference rejects the whole batch; nothing is sent). Contact batches return per-item results (`Affected` / `AffectedContactIds` / `NotProcessed`) — the authoritative record of what actually happened; report exact counts ("reassigned 48 of 50"). ## Enum quick reference Every closed value set the server declares, in one place. All are case-insensitive unless noted. | Field | Values | Used by | | --------------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------- | | `channel` | `Email`, `LinkedIn` | `send_inbox_reply`, `list_pending_approvals` filter | | Per-sequence contact status | `Active`, `Paused`, `Finished`, `Inactive`, `OutOfOffice` | `change_status_in_sequence` | | Sequence search status | `New`, `Active`, `Paused` | `search_sequences` | | Reply mode | `Review`, `Autonomous` (+ `sendExistingDrafts` boolean) | `set_sequence_reply_mode` | | `toneOfVoice` | `Confident`, `Persuasive`, `Witty`, `Straightforward`, `Empathetic` | reply handlers, reengagement cards | | `responseLength` | `SuperShort`, `Short`, `Medium`, `Long` | reply handlers, reengagement cards | | `taskType` | `ToDo`, `Call`, `Meeting`, `LinkedIn`, `ManualEmail`, `Sms`, `WhatsApp` | `create_task`, `list_my_tasks` | | `linkedInTaskType` | `Message`, `Connect`, `InMail`, `ViewProfile` | `create_task` (required when `taskType=LinkedIn`) | | `callResolution` | `Positive`, `ToCall`, `Negative` | `complete_task` (recommended for Call tasks) | | Playbook visibility | `Team` (default), `Organization` | `create_playbook`, `duplicate_playbook` | | `category` | `integrations`, `reporting`, `sequences`, `contacts`, `email`, `linkedIn`, `ai`, `other` | `report_unsupported_request` | | `sortMode` | `NewestFirst` (default), `OldestFirst` | `list_pending_approvals` | ## Response envelopes **Transport.** Responses are SSE frames (`text/event-stream`) whose `data:` lines carry ordinary JSON-RPC payloads. Read the last `data:` frame for the result. **Success.** A successful `tools/call` returns `result.isError = false`, and the actual payload is a JSON string inside `result.content[0].text`: ```json theme={null} { "Success": true, "Data": { "Items": [ ... ], "HasMore": false } } ``` **Error.** Tool failures are **not** HTTP errors — they come back as **HTTP 200**, JSON-RPC success, with `result.isError = true` and the error as a JSON string in `result.content[0].text`: ```json theme={null} { "Success": false, "ErrorCode": "InvalidArguments", "ErrorMessage": "..." } ``` Parse the inner JSON; branch on `Success`, then on `ErrorCode`. Real captured examples: ```json theme={null} {"Success":false,"ErrorCode":"InvalidArguments","ErrorMessage":"Tool 'reply_get_sequence_steps' arguments failed validation: SequenceId: 'Sequence Id' must be greater than '0'."} {"Success":false,"ErrorCode":"InvalidArguments","ErrorMessage":"Tool 'reply_send_inbox_reply' is missing required argument(s): message. Supply a real value for each; null, empty strings, and empty arrays are not accepted for required fields."} {"Success":false,"ErrorCode":"InvalidArguments","ErrorMessage":"Tool 'reply_search_contacts' arguments failed validation: : At least one of Email or LinkedIn must be provided. If the user gave only a name or company, ask them for an email address or LinkedIn URL instead."} ``` ## Error model Handle failures at three layers: 1. **Transport / auth.** `401` (missing/invalid key), `403` (valid key, missing scope or plan feature), `429` (rate limit — back off using `X-Rate-Limit-Reset`), `5xx` (transient). 2. **Tool-level `ErrorCode`s** (inside the envelope): `InvalidArguments`, `NotFound`, `Forbidden`, `Conflict`, `InvalidInput`, `InvalidParameter`, `UpstreamFailure`, `ServiceUnavailable`, plus domain-specific codes named per tool (`NoEmailAccounts`, `NoContacts`, `ContactLimitExceeded`, `ChannelMismatch`, `ContactOptedOut`, `ThreadSendFailed`, `InvalidStatusTransition`, `ArticleNotFound`, `PERMISSION_DENIED`, …). Each tool's description states which codes it can return and what to do about each. 3. **Per-item partial results.** Batch tools report per-contact skips in `NotProcessed` (e.g. `ContactAlreadyInSequence`, `ContactInBlackList`, `NotFound`) while the call as a whole succeeds. Read them; never claim an item succeeded unless it appears in the affected list. ## Safe-retry matrix A timed-out **send** may already have succeeded server-side. Verify with a read before retrying anything that reaches a prospect. | When | Tools | Policy | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------- | | Auto-retry once on transient `ServiceUnavailable` / `UpstreamFailure` / timeout | all read tools — `search_*`, `list_*`, `get_*`, `filter_*`, `*_stats`, `compare_*`, `get_app_map`, `search_knowledge_base` | Safe to retry | | Retry only **after a verifying read** | `create_*`, `update_*`, `add_contact_to_sequence`, `change_status_in_sequence`, `assign_*`, `attach_*`, `complete_task`, `mark_contacts_as_replied` | Read first, then retry | | **Never** auto-retry — confirm with the user first | `send_inbox_reply`, `approve_message`, `bulk_approve_messages`, `reject_message`, `start_sequence`, `blacklist_contact`, `change_contact_owner`, switching to Autonomous | Verify server state, then decide | Next: [Building agents](/mcp/agent-guide) for how to sequence these calls, and the [tool reference](/mcp/tools) for the full catalog. # Tool reference Source: https://docs.reply.io/mcp/tools The full catalog of all 70 Reply MCP tools, grouped by domain, with safety annotations. All 70 tools, grouped by domain. This is a **map**, not a schema dump — the authoritative, per-argument JSON schema for every tool is served live by `tools/list`, and an agent should read it from there. Each tool's served description also states its exact ID rules, enum values, batch limits, and per-code failure guidance. See the [tool contract](/mcp/tool-contract) for the rules shared across all of them. **Legend:** 📖 read-only (`readOnlyHint`) · ✏️ mutation (`destructiveHint`) · ⭐ high-stakes (prospect-visible or irreversible — always confirm; see [Building agents](/mcp/agent-guide#high-stakes-tools)). ## Sequences ### Discover & inspect | Tool | | Purpose | | ------------------------------------ | :-: | ----------------------------------------------------------------------------------- | | `reply_search_sequences` | 📖 | Find sequences by name / status / archive flag; returns per-sequence summary fields | | `reply_get_sequence_steps` | 📖 | List a sequence's ordered steps (type, delay, position, variant count) | | `reply_get_sequence_step_variants` | 📖 | Read a message step's A/B content variants (subject, body) | | `reply_get_sequence_stats` | 📖 | Email + LinkedIn performance metrics for one sequence | | `reply_compare_sequence_performance` | 📖 | Side-by-side metrics for up to 25 sequences | ### Control & configuration | Tool | | Purpose | | ------------------------------------------- | :-: | -------------------------------------------------- | | `reply_start_sequence` | ✏️⭐ | Start or resume a sequence so it begins sending | | `reply_pause_sequence` | ✏️ | Pause a sequence; halt in-flight scheduled steps | | `reply_add_contact_to_sequence` | ✏️⭐ | Enroll up to 100 existing contacts into a sequence | | `reply_change_status_in_sequence` | ✏️ | Set one contact's per-sequence status | | `reply_assign_email_account_to_sequence` | ✏️ | Link a mailbox to a sequence | | `reply_assign_linkedin_account_to_sequence` | ✏️ | Link a LinkedIn account to a sequence | | `reply_assign_schedule_to_sequence` | ✏️ | Set the sending schedule (business-hours window) | | `reply_attach_offer_to_sequence` | ✏️ | Attach an offer to an AI SDR sequence | | `reply_attach_playbook_to_sequence` | ✏️ | Attach a playbook to an AI SDR sequence | | `reply_attach_knowledge_base_to_sequence` | ✏️ | Attach a knowledge base to an AI SDR sequence | | `reply_set_sequence_reply_mode` | ✏️⭐ | Set Jason's Review / Autonomous reply mode | ## Contacts | Tool | | Purpose | | -------------------------------- | :-: | ----------------------------------------------------------------- | | `reply_search_contacts` | 📖 | Look up contacts by exact email or LinkedIn URL | | `reply_filter_contacts` | 📖 | List contacts by list/sequence membership and/or free-text search | | `reply_create_contact` | ✏️ | Create a contact (needs a name + email or LinkedIn URL) | | `reply_update_contact` | ✏️ | Patch fields on an existing contact | | `reply_get_contact_activity` | 📖 | Activity history for one contact (sends, opens, replies, calls) | | `reply_mark_contacts_as_replied` | ✏️ | Mark up to 100 contacts as replied (or clear the flag) | | `reply_change_contact_owner` | ✏️⭐ | Reassign up to 100 contacts to another user | | `reply_blacklist_contact` | ✏️⭐ | Blacklist a contact's email (or whole domain) from outreach | ## Inbox & conversations | Tool | | Purpose | | ----------------------------- | :-: | --------------------------------------------------------- | | `reply_get_inbox_emails` | 📖 | List inbox threads (email + LinkedIn) with short previews | | `reply_send_inbox_reply` | ✏️⭐ | Send a reply on an existing thread (body only in v1) | | `reply_change_inbox_category` | ✏️ | Assign or clear a thread's workspace category | ## Jason AI SDR ### Approvals & autopilot | Tool | | Purpose | | ------------------------------ | :-: | --------------------------------------------------------------- | | `reply_list_pending_approvals` | 📖 | The queue of Jason drafts awaiting approval | | `reply_approve_message` | ✏️⭐ | Approve one draft and send it immediately | | `reply_bulk_approve_messages` | ✏️⭐ | Approve and send up to 100 drafts (atomic batch) | | `reply_reject_message` | ✏️⭐ | Reject a draft **and remove the contact from the sequence** | | `reply_regenerate_message` | ✏️ | Ask Jason to rewrite a pending draft (optionally with feedback) | ### Knowledge bases | Tool | | Purpose | | ------------------------------------ | :-: | ------------------------------------------------------------- | | `reply_list_knowledge_bases` | 📖 | List Jason knowledge bases | | `reply_get_knowledge_base` | 📖 | Full detail of one knowledge base (instructions, URL sources) | | `reply_create_knowledge_base` | ✏️ | Create a knowledge base | | `reply_update_knowledge_base` | ✏️ | Rename or edit a knowledge base's instructions | | `reply_add_knowledge_base_source` | ✏️ | Add a web-page URL source to a knowledge base | | `reply_delete_knowledge_base_source` | ✏️ | Remove a URL source from a knowledge base | ### Reply handlers | Tool | | Purpose | | ---------------------------- | :-: | -------------------------------------------------- | | `reply_list_reply_handlers` | 📖 | List reply handlers in a knowledge base | | `reply_get_reply_handler` | 📖 | Full detail of one reply handler | | `reply_create_reply_handler` | ✏️ | Add a reply handler (question type → instructions) | | `reply_update_reply_handler` | ✏️ | Patch a reply handler | | `reply_delete_reply_handler` | ✏️ | Remove a reply handler | ### Reengagement cards | Tool | | Purpose | | -------------------------------- | :-: | ------------------------------------------------------ | | `reply_list_reengagement_cards` | 📖 | List reengagement (win-back) cards in a knowledge base | | `reply_get_reengagement_card` | 📖 | Full detail of one reengagement card | | `reply_create_reengagement_card` | ✏️ | Add a reengagement card (with send-after days) | | `reply_update_reengagement_card` | ✏️ | Patch a reengagement card | | `reply_delete_reengagement_card` | ✏️ | Remove a reengagement card | ### Offers | Tool | | Purpose | | ----------------------------------- | :-: | --------------------------------------------------------- | | `reply_list_offers` | 📖 | List Jason offers (id + name) | | `reply_get_offer` | 📖 | Full offer content (ICP, value props, proof points, CTAs) | | `reply_create_offer` | ✏️ | Create an offer Jason can pitch | | `reply_update_offer` | ✏️ | Patch an offer | | `reply_generate_offer_from_website` | 📖 | Draft offer fields from a company website (does not save) | ### Playbooks | Tool | | Purpose | | -------------------------- | :-: | --------------------------------------------------- | | `reply_list_playbooks` | 📖 | List Jason playbooks (id, name, visibility) | | `reply_get_playbook` | 📖 | Full playbook, including the instruction body | | `reply_create_playbook` | ✏️ | Create a playbook (Team or Organization visibility) | | `reply_update_playbook` | ✏️ | Patch a playbook | | `reply_duplicate_playbook` | ✏️ | Duplicate a playbook into a new one | ## Tasks | Tool | | Purpose | | --------------------- | :-: | ------------------------------------------------------------------- | | `reply_list_my_tasks` | 📖 | List your tasks, filterable by type / status / due window / contact | | `reply_create_task` | ✏️ | Create a standalone task (ToDo / Call / Meeting / LinkedIn / …) | | `reply_complete_task` | ✏️ | Mark a task completed (with optional call resolution) | ## Workspace resolvers & accounts | Tool | | Purpose | | ------------------------------ | :-: | ------------------------------------------------------------ | | `reply_list_email_accounts` | 📖 | List mailboxes with connection status, daily limits, tags | | `reply_list_linkedin_accounts` | 📖 | List connected LinkedIn accounts with health and tier | | `reply_list_schedules` | 📖 | List sending schedules (timezone, default flag, slot counts) | | `reply_search_lists` | 📖 | Resolve a contact list name to its `ListId` | | `reply_search_team_members` | 📖 | Resolve a teammate name/email to their `UserId` | ## Help & meta | Tool | | Purpose | | ---------------------------------- | :-: | ------------------------------------------------------------ | | `reply_search_knowledge_base` | 📖 | Search the Reply.io Help Center for how-to articles | | `reply_get_knowledge_base_article` | 📖 | Read a full Help Center article by slug | | `reply_get_app_map` | 📖 | Catalog of app areas with in-app navigation steps and links | | `reply_report_unsupported_request` | 📖 | Log a capability Reply.io doesn't have, for the product team | ## Regenerate this reference This catalog is not hand-maintained trust — regenerate it in seconds by probing the running server: ```bash theme={null} # 1) initialize curl -s -X POST https://mcp.reply.io/ \ -H "Authorization: Bearer YOUR_REPLY_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize", "params":{"protocolVersion":"2025-06-18","capabilities":{}, "clientInfo":{"name":"probe","version":"0.1"}}}' # 2) list tools curl -s -X POST https://mcp.reply.io/ \ -H "Authorization: Bearer YOUR_REPLY_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' ``` Responses are SSE — take the JSON after the last `data:` line. If the returned tool set differs from this page, the server is newer — **trust the server**. # Skill catalog Source: https://docs.reply.io/skills/catalog Every outcome-level Reply skill — availability, composed APIs, inputs, and outputs. All outcome-level skills in the [Reply Agent Skill](https://github.com/replyio/reply-skill). Available skills ship today as workflow files in the repo; coming-soon entries depend on API endpoints that aren't generally available yet and will join the same skill when those ship. Install once, get all available workflows — see [Install](/skills/overview#install). ## Available ### Import prospects *CSV in, deduplicated contacts out — mapped, verified, and organized into a list.* Previews the parsed rows and column mapping, confirms dedupe strategy and destination, imports in batches of at most 1000, then verifies list membership. Executes via [`reply api`](/cli/overview#raw-api-access) against `POST /v3/contacts/import`. | | | | ----------------- | -------------------------------------------------------------------------------------------------- | | **Workflow file** | `workflows/import-prospects.md` | | **Composes** | Contact Data API | | **Inputs** | A CSV file (or pasted rows); dedupe preference (skip vs update); optional target list | | **Outputs** | Added / updated / skipped / failed counts with per-row reasons; a verified list ready for outreach | | **Guide** | [Import and clean contacts](/guides/import-contacts) | ### Launch outreach *Verify accounts, build the sequence, enroll contacts, and start — with a confirmation gate before anything sends.* The full launch checklist as one workflow: check sending accounts, create or select the sequence, preview the enrollment, add contacts, and start — only after explicit confirmation. Complex step editing (A/B variants on live sequences, LinkedIn steps) is handed off to the Reply app in v1. | | | | ----------------- | ------------------------------------------------------------------------------------------------------------- | | **Workflow file** | `workflows/launch-outreach.md` | | **Composes** | Sequences, Templates & Schedules, Mailbox Management, Contact Data | | **Inputs** | Target contacts (list, fresh import, or IDs/emails); a sequence to reuse, or a name plus drafts | | **Outputs** | A running sequence with mailboxes, schedule, and contacts; sequence ID, enrollment counts, skips with reasons | | **Guide** | [Launch multichannel outreach](/guides/launch-outreach) | ### Manage replies *Triage the inbox, surface interested prospects, and send approved replies.* Reads the inbox, groups threads by category and meeting intent, presents full conversation context, drafts responses with the user, and sends only after showing the exact text and getting confirmation. Fully automated reply policies (auto-answer via webhooks) are not in v1 — every send is human-approved. Previously listed as "Handle Replies" on agents.reply.io — the workflow file name `manage-replies` is the canonical name. | | | | ----------------- | ------------------------------------------------------------------------------------------------ | | **Workflow file** | `workflows/manage-replies.md` | | **Composes** | Conversations & Inbox API | | **Inputs** | Optional filters (category, sequence, unread, meeting intent) | | **Outputs** | Sent replies (each explicitly approved) and categorized threads; a queue still needing attention | | **Guide** | [Convert replies into meetings](/guides/convert-replies-to-meetings) | ### Analyze performance *Turn raw reporting data into decisions — what to scale, pause, or rewrite.* Pulls the account email overview and per-sequence stats, benchmarks deliverability, copy, and targeting, flags stalled or degraded sequences, and recommends concrete changes — pausing or edits happen only after explicit approval. | | | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | **Workflow file** | `workflows/analyze-performance.md` | | **Composes** | Analytics, Sequences | | **Inputs** | A time window and the sequences (or whole account) to analyze | | **Outputs** | A performance readout (delivered, opens, replies, interested, meetings) with diagnosis; 1–2 recommended actions, executed only on confirmation | | **Guide** | [Decide what to scale or fix](/guides/analyze-performance) | ## Coming soon These skills depend on API endpoints that are not generally available yet. They are not installable today. ### Find prospects *Turn an ICP description into a saved, deduplicated prospect list.* Wraps Live Data search, preview, and contact import into one operation — translates a natural-language ICP into structured filters, previews result size before spending credits, and lands the output as a named contact list. **Blocked on:** the Live Data / prospect-search API. ### Build an ICP *Derive an ideal customer profile from your best existing customers or a business description.* Analyzes which segments actually convert (from reporting data when available) and produces a structured ICP that feeds directly into Find prospects. **Blocked on:** the Live Data / prospect-search API. ### Enrich contacts *Fill missing emails, phones, and firmographics across a whole contact list.* Runs waterfall enrichment over a list, schedules email validation on the results, and writes everything back to contact records. **Blocked on:** the Enrichment API. ### Book meetings *Convert interested replies into scheduled meetings via Reply's booking calendar.* Detects meeting intent, drives the scheduling exchange in-thread, and shares the booking calendar link. Booking itself happens through Reply's in-app scheduling product — there is no book-a-meeting API endpoint today; the skill manages the conversation around booking and verifies outcomes in the meetings report. # Reply Agent Skill Source: https://docs.reply.io/skills/overview Install one skill and your agent learns the core outreach workflows — executed through the reply CLI with confirmation gates. The [Reply.io Agent Skill](https://github.com/replyio/reply-skill) packages the core outreach workflows as one installable skill. A skill is a folder of markdown instructions (`SKILL.md` plus workflow files) that an agent platform like Claude Code loads on demand — it encodes which commands to run, in what order, what to verify, and where to stop for human confirmation. No runtime code: ``` AI agent → Agent Skill (workflows, guardrails) → reply CLI → Reply.io v3 API ``` The skill decides *what* to do; the [CLI](/cli/overview) does it. You can use the CLI without the skill; the skill requires the CLI. ## Install ```bash theme={null} npm i -g reply-cli reply auth login # OAuth in the browser; or export REPLY_API_KEY=... git clone https://github.com/replyio/reply-skill.git ~/.claude/skills/reply ``` Sign-in options and credential precedence: [Reply CLI → Authenticate](/cli/overview#authenticate). Key creation and scopes: [Authentication](/api-reference/authentication). ## Run your first skill Once installed, just ask your agent in natural language: * *"Import this CSV and skip duplicates"* * *"Show me interested replies from this week"* * *"Which sequences are underperforming?"* * *"Launch outreach to the SaaS founders list"* (the skill will gate the start behind your confirmation) ## What's in v1 Four workflows, each with previews, verification steps, and hard confirmation gates — nothing sends, starts, or deletes without explicit approval: | Workflow | What it does | | --------------------- | ------------------------------------------------------------------- | | `import-prospects` | CSV → mapping preview → dedupe → list → verify | | `launch-outreach` | Account & schedule checks → sequence → enrollment → confirmed start | | `manage-replies` | Inbox triage → thread context → approved reply → categorize | | `analyze-performance` | Reports + per-sequence stats → diagnosis → recommendations | See the [Skill catalog](/skills/catalog) for every outcome-level skill — including the coming-soon set — with inputs, outputs, and the APIs each one composes. ## How it relates to MCP MCP gives an agent **tools** (individual operations). The skill gives it **procedure** — multi-step workflows with confirmation gates and verification. They compose: an agent can follow the skill's procedure using MCP tools or CLI commands. See [Choose your interface](/agents/choose-your-interface). ## Source * Repo: [github.com/replyio/reply-skill](https://github.com/replyio/reply-skill) * Execution layer: [Reply CLI](/cli/overview) ([npmjs.com/package/reply-cli](https://www.npmjs.com/package/reply-cli)) # Webhook event payloads Source: https://docs.reply.io/webhook-event-payloads Example payloads for every webhook event. When a webhook subscription fires, Reply sends a JSON payload to your configured URL. This page documents the payload for each supported event type. The examples match the structure of real webhook deliveries. ## Event envelope Every webhook delivery includes the same top-level event envelope: ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "email_replied", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, // event-specific fields follow, flat at the top level } ``` | Field | Type | Notes | | ----------------------- | ------------ | ----------------------------------------------------------------------- | | `event.date` | ISO-8601 UTC | Time the event occurred in Reply. | | `event.id` | UUID | Unique event identifier. Use it for idempotency when processing events. | | `event.type` | string | Event type. Matches the subscription's `eventType`. | | `event.user_id` | int | ID of the Reply user associated with the subscription. | | `event.team_id` | int | ID of the team associated with the event. | | `event.subscription_id` | int | ID of the subscription that triggered the event. | ## Shared conventions * Property names use `snake_case`, for example `event_type`, `sequence_fields`, and `reply_message_url`. * Enum values are PascalCase strings, for example `"Personal"`, `"EmailDetected"`, and `"Hard"`. * Timestamps use ISO-8601 UTC format with millisecond precision. * Events associated with a contact include a `contact_fields` object. Use `contact_fields.id` as the stable contact identifier. * If the subscription was created with `includeProspectCustomFields: true`, a `contact_custom_fields` object is also included. * Events associated with a sequence include a `sequence_fields` object. * If `SequenceId` is `0`, the event is not associated with a sequence and `sequence_fields` may be empty or omitted. * Email-related events respect the subscription's `includeEmailUrl` and `includeEmailText` settings. Disabled fields are omitted from the payload. ## Reusable blocks The following objects appear in multiple event payloads. ### `contact_fields` ```json theme={null} { "id": 12345, "email": "prospect@example.com", "first_name": "Test", "last_name": "Prospect", "full_name": "Test Prospect", "title": "Test Title", "company": "Test Company", "linkedin_profile_url": "https://linkedin.com/in/test", "city": "Test City", "state": "Test State", "country": "Test Country", "time_zone_id": "America/Los_Angeles", "phone": "+1234567890", "domain": "example.com", "company_size": "51-200 employees", "industry": "Software", "linkedin_sales_navigator": "https://www.linkedin.com/sales/people/test", "linkedin_recruiter": "https://www.linkedin.com/recruiter/people/test" } ``` ### `contact_custom_fields` Only included when the subscription was created with `payloadConfig.includeProspectCustomFields: true`. Keys match the custom field names configured on the contact. ```json theme={null} { "Custom Field 1": "Custom Value 1" } ``` ### `sequence_fields` ```json theme={null} { "id": 200, "name": "Test Sequence", "step_number": 1 } ``` *** ## Event reference ### `email_replied` **When it fires:** Once per recorded email reply — when Reply detects an incoming reply to a sequence email, or a direct reply that is not tied to a sequence. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "email_replied", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "email_account_id": 1, "sent_email_id": 999, "reply_date": "2026-04-21T09:30:00.000Z", "reply_message_id": "test-reply-msg-id", "email_from": "account@example.com", "reply_message_url": "https://example.com/test-email-blob", "email_text": "…", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `email_account_id` * The Reply email account that received the reply. * `sent_email_id` * The sequence email that was replied to. `null` for direct replies that are not tied to a sequence email. * `email_from` * Present when the replying email account is known. * `reply_message_url` * Included when `includeEmailUrl: true`. * `email_text` * Included when `includeEmailText: true`. * `sequence_fields` * Omitted for direct replies that have no sequence context. * `contact_custom_fields` * Included when `includeProspectCustomFields: true`. * `sequence_fields` includes `id`, `name`, and `step_number`. ### `reply_categorized` **When it fires:** An email reply is categorized automatically by Reply or manually by a user. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "reply_categorized", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "sent_email_id": 999, "reply_date": "2026-04-21T09:30:00.000Z", "reply_message_id": "test-reply-msg-id", "reply_inbox_category_name": "Interested", "reply_message_url": "https://example.com/test-email-blob", "email_text": "…", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `reply_inbox_category_name` * Human-readable category name. * Built-in values include: * `"No categories"` * `"Interested"` * `"Not interested"` * `"Do not contact"` * `"Not now"` * `"Forwarded"` * `"Meeting intent"` * Teams can create custom categories. Treat this field as a free-form string. * `reply_message_id` * May be `null` for older replies where the original message ID was not captured. * `reply_date` * May be `null` for older replies where the original timestamp is unavailable. * `reply_message_url` * Included when `includeEmailUrl: true` and a stored reply is available. * `email_text` * Included when `includeEmailText: true` and the reply body can be extracted. * `contact_custom_fields` * Included when `includeProspectCustomFields: true`. * `sequence_fields` includes `id`, `name`, and `step_number`. Omitted if the reply is not associated with a sequence. ### `email_sent` **When:** Reply sends an email from a sequence step. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "email_sent", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "email_account_id": 1, "sent_email_id": 999, "sent_email_message_id": "test-message-id", "sent_email_date": "2026-04-21T09:30:00.000Z", "sent_message_url": "https://example.com/test-email-blob", "email_text": "…", "email_from": "account@example.com", "sent_email_variant": "A", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `sent_email_variant` identifies the A/B variant that was sent. Omitted when the step has only one variant. * `sent_message_url` is included when `includeEmailUrl` is enabled and the message blob is available. * `email_text` is included when `includeEmailText` is enabled and the message body can be parsed. * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id`, `name`, and `step_number`. ### `email_opened` **When:** A recipient opens a tracked email. Opens from IP addresses in the user's exclusion list are ignored. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "email_opened", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "email_account_id": 1, "sent_email_id": 999, "sent_email_message_id": "test-message-id", "email_open_date": "2026-04-21T09:30:00.000Z", "opens_count": 1, "email_from": "account@example.com", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `opens_count` is the total number of opens for the email. It increases each time the email is opened. * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id`, `name`, and `step_number`. ### `email_link_clicked` **When:** A recipient clicks a tracked link in an email. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "email_link_clicked", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "email_link_url": "https://example.com/test-link", "email_from": "account@example.com", "contact_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### `email_bounced` **When:** A sent email bounces or is rejected by the recipient's mail server. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "email_bounced", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "email_account_id": 1, "sent_email_id": 999, "bounce_date": "2026-04-21T09:30:00.000Z", "bounce_type": "Hard", "bounce_message_id": "test-bounce-id", "sent_message_url": "https://example.com/test-email-blob", "email_text": "…", "email_from": "account@example.com", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `bounce_type` can be: * `Unknown` * `Soft` * `Hard` * `GmailApiLimitWarning` * `Office365LimitWarning` * `MailboxFull` * `AuthenticationFailure` * `SpamRejection` * `PolicyViolation` * `sent_message_url` is included when `includeEmailUrl` is enabled and the message blob is available. * `email_text` is included when `includeEmailText` is enabled and the message body can be parsed. * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id`, `name`, and `step_number`. ### `email_auto_reply` **When:** Reply identifies an incoming message as an auto-reply or out-of-office message. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "email_auto_reply", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "email_account_id": 1, "sent_email_id": 999, "reply_date": "2026-04-21T09:30:00.000Z", "reply_message_id": "test-reply-id", "reply_subject": "Out of Office: Test Subject", "reply_type": "AutoReply", "reply_message_url": "https://example.com/test-email-blob", "email_text": "…", "email_from": "account@example.com", "user_name": "Test User", "user_email": "user@example.com", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `reply_type` is: * `AutoReply` for automatic responder messages * `OutOfOffice` for out-of-office messages * `email_account_id` may be `null`. * `email_from` is included only when the email account is known. * `reply_message_url` is included when `includeEmailUrl` is enabled. * `email_text` is included when `includeEmailText` is enabled and the message body can be parsed. * `user_name` and `user_email` identify the Reply user who owns the sequence when the event is generated. * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id`, `name`, and `step_number`. ### `email_account_connection_lost` **When:** A connected mailbox can no longer authenticate, such as after an OAuth revocation or password change. This is an account-level event and does not include contact or sequence information. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "email_account_connection_lost", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "email_account_id": 1, "email_account_address": "account@example.com" } ``` ### `email_account_error` **When:** A connected mailbox reports an IMAP or SMTP error, such as an authentication failure, send failure, health check failure, reputation issue, or sending limit. The event is generated each time the underlying error changes to a non-empty value. Clearing the error does not generate an event. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "email_account_error", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "email_account_id": 1, "email_account_error": "Sending: SMTP authentication failed", "email_account_address": "account@example.com" } ``` ### Field notes * `email_account_error` is a free-form error message. * Error messages always begin with either: * `Receiving:` for IMAP-related errors * `Sending:` for SMTP-related errors * `email_account_address` may be omitted if the email account can no longer be loaded. ### `contact_finished` **When:** A contact's participation in a sequence ends. This can happen when the contact completes the sequence, reaches a terminal status, or is manually finished. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "contact_finished", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "finish_reason": "Replied", "finished_date": "2026-04-21T09:30:00.000Z", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence" } } ``` ### Field notes `finish_reason` can be one of: | Value | Description | | :------------------- | :--------------------------------------------------- | | `Replied` | The contact replied to a sequence email. | | `Bounced` | An email bounced and the contact was removed. | | `Manual` | A user manually finished the contact. | | `FinishedAfterXdays` | The contact reached the sequence's maximum duration. | | `None` | No specific reason was recorded. | | `Called` | The contact was finished after a phone call. | | `OptOut` | The contact opted out. | | `MeetingBooked` | A meeting was booked with the contact. | | `ForbiddenStep` | The next step was blocked by content guardrails. | Additional fields: * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id` and `name`. The whole sequence has ended, so this event is not tied to a single step and `step_number` is not included. ### `contact_opted_out` **When:** A contact opts out of future outreach. This event is generated when a contact: * Clicks an unsubscribe link * Is manually opted out by a user * Is marked as **Do Not Contact** All three scenarios generate the same event and payload. The event does not indicate which action caused the opt-out. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "contact_opted_out", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "opt_out_date": "2026-04-21T09:30:00.000Z", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field otes * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id`, `name`, and `step_number`. ### `contact_called` **When:** A call with a contact reaches a final state, such as answered, missed, busy, timed out, or logged manually. The event is generated after call details have been collected and are ready to deliver. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "contact_called", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "from_number": "+1234567890", "duration": 60, "disposition": "Answered", "resolution": "Positive", "notes": "Spoke with prospect, scheduled a follow-up.", "recording_url": "https://example.com/test-call-recording", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `from_number` is the phone number used to place the call. * `duration` is the call length in seconds. It is `0` for manually logged calls and calls that never connected. * `disposition` can be: * `Answered` * `LoggedManually` * `NoAnswer` * `Busy` * `Fail` * `resolution` can be one of Reply's built-in values (`Positive`, `ToCall`, `Negative`) or a custom resolution defined by the team. Treat this field as a free-form string. * `notes` contains any notes entered by the user. It is `null` when no notes were saved. * `recording_url` contains a recording URL when a recording is available. It is `null` when the call was not recorded. * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id`, `name`, and `step_number`. `step_number` is `0` for calls not tied to a sequence step. ### `linkedin_connection_request_sent` **When:** Reply sends a LinkedIn connection request as part of a sequence step. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "linkedin_connection_request_sent", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "sender_linkedin_account_id": 50, "initial_message": "Test connection request", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence" } } ``` ### Field notes * `sender_linkedin_account_id` is the Reply LinkedIn account ID. It is not a LinkedIn public identifier. * `initial_message` contains the connection request note that was sent. It may be `null` if no note was included. * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id` and `name`. `step_number` is not included for this event. ### `linkedin_connection_request_accepted` **When:** A LinkedIn connection request previously sent through Reply is accepted. Only connection requests sent through Reply generate this event. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "linkedin_connection_request_accepted", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "sender_linkedin_account_id": 50, "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id`, `name`, and `step_number`. ### `linkedin_message_sent` **When:** Reply sends a LinkedIn message or InMail. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "linkedin_message_sent", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "sender_linkedin_account_id": 50, "initial_message": "Test message", "is_inmail": false, "is_voice_attached": false, "linkedin_message_id": "test-msg-id", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `linkedin_message_id` is a Reply-generated message identifier. It is not a LinkedIn message ID. * `is_inmail` is `true` for InMail messages and `false` for regular LinkedIn messages. * `is_voice_attached` is `true` when a voice attachment was included. * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields` includes `id`, `name`, and `step_number`. ### `linkedin_message_replied` **When:** A contact replies to a LinkedIn conversation associated with a sequence contact. Only replies linked to known contacts in Reply generate this event. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "linkedin_message_replied", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "sender_linkedin_account_id": 50, "linkedin_message_id": "01234567-89ab-cdef-0123-456789abcdef", "linkedin_message": "Test reply", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `linkedin_message_id` is a Reply-generated identifier. It is not a LinkedIn message ID. * `linkedin_message` contains the reply text. * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `sequence_fields.name` and `sequence_fields.step_number` are always included. * `sequence_fields.id` is included only when the contact is currently associated with a sequence. ### `linkedin_reply_categorized` **When:** Reply assigns a category to a LinkedIn conversation. A separate event is generated for each affected conversation. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "linkedin_reply_categorized", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "linkedin_thread_id": 1, "reply_inbox_category_name": "Interested", "last_reply_date": "2026-04-21T09:30:00.000Z", "linkedin_message": "Test reply", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `reply_inbox_category_name` can be one of: * `No categories` * `Interested` * `Not interested` * `Do not contact` * `Not now` * `Forwarded` * `Meeting intent` * LinkedIn categories do not support custom category names. * `last_reply_date` is included when available. * `contact_custom_fields` is included when `includeProspectCustomFields` is enabled. * `linkedin_message` contains the raw reply text from the contact. It is included only when `includeLinkedInMessageText` is enabled. * `sequence_fields` includes `id`, `name`, and `step_number` when the conversation is associated with a sequence; it is empty when it is not. ### `autopilot_stopped` **When:** An evergreen sequence's autopilot is disabled. This event is generated only for the reasons listed in `autopilot_error_message`. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "autopilot_stopped", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "autopilot_error_message": "the active contacts limit has been reached", "user_name": "Test User", "user_email": "user@example.com", "sequence_owner_name": "Test Owner", "sequence_owner_email": "owner@example.com", "sequence_fields": { "id": 200, "name": "Test Sequence" } } ``` ### Field notes `autopilot_error_message` is one of: * `the sequence has been deactivated` * `the active contacts limit has been reached` * `there are no more contacts/companies matching the filter criteria` Additional fields: * `user_name` and `user_email` identify the user who triggered the deactivation. * `sequence_owner_name` and `sequence_owner_email` identify the sequence owner. * Owner fields may be omitted if the corresponding user cannot be resolved. **Team accounts** If the user who triggered the deactivation is not the sequence owner, Reply generates two events: * One for the acting user * One for the sequence owner Both events contain the same sequence information and error message. ### `linkedin_account_alerts` **When:** Reply detects a LinkedIn account issue that requires attention. Examples include a disconnected Sales Navigator account, exhausted InMail credits, or a connection request limit. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "linkedin_account_alerts", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "linkedin_id": 50, "linkedin_name": "Test LinkedIn Account", "linkedin_account_alert": "Sales Navigator is disconnected. Please reconnect your LinkedIn account to continue sending InMail steps.", "team_name": "Test Workspace", "linkedin_owner_name": "Test User", "linkedin_owner_email": "owner@example.com" } ``` ### Field notes * `linkedin_id` and `linkedin_name` identify the LinkedIn account associated with the alert. * `linkedin_account_alert` contains a human-readable description of the issue. * `team_name` may be omitted if the workspace has no name. * `linkedin_owner_name` and `linkedin_owner_email` may be omitted if the account owner cannot be resolved. ### Alert types | Alert | Description | Re-fire interval | | :------------------------------------ | :---------------------------------------- | :------------------------ | | `SalesNavigatorDisconnected` | Sales Navigator is disconnected. | Up to once every 12 hours | | `InMailCreditsExhausted` | No InMail credits remain. | Up to once every 24 hours | | `ConnectionRequestWeeklyLimitReached` | Weekly LinkedIn connection limit reached. | Up to once every 24 hours | ### `contact_replied` **When it fires:** Each time a sequence contact is recorded as **replied** — Reply detects a reply to a sequence email (`reason: "EmailDetected"`), a sequence LinkedIn message (`reason: "LinkedInDetected"`), or a sequence SMS (`reason: "SmsDetected"`), or a user or the API marks the contact as replied (`reason: "StatusSetManually"`). This is a channel-agnostic **status** signal: subscribe to it once to learn whenever a contact enters the replied state, regardless of channel, instead of combining `email_replied`, `linkedin_message_replied`, and manual actions yourself. It carries who replied, which sequence/step, when, and why — not the message content. For channel-specific detail (message body, mailbox, sender account) subscribe to the matching per-channel webhook and correlate by `reply_message_id`. ```json theme={null} { "event": { "date": "2026-04-21T09:30:00.000Z", "id": "4c1b9e74-5ac3-4b0f-9a60-2a37a9b4a2d1", "type": "contact_replied", "user_id": 1234, "team_id": 100, "subscription_id": 42 }, "reply_date": "2026-04-21T09:30:00.000Z", "reply_message_id": "test-reply-msg-id", "reason": "EmailDetected", "contact_fields": { "…": "see above" }, "contact_custom_fields": { "…": "see above" }, "sequence_fields": { "id": 200, "name": "Test Sequence", "step_number": 1 } } ``` ### Field notes * `reason` * `"EmailDetected"` when Reply detects a reply to a sequence email. * `"LinkedInDetected"` when Reply detects a reply to a sequence LinkedIn message. * `"SmsDetected"` when Reply detects a reply to a sequence SMS. * `"StatusSetManually"` when a user or the API marks the contact as replied. * `reply_message_id` * Correlation key to the matching per-channel webhook (`email_replied` / `linkedin_message_replied`): email reply message id, LinkedIn message id, or SMS provider message id. `null` for manually marked replies, which carry no stored message. * `contact_fields` * The contact who replied. See the shared [`contact_fields`](#contact_fields) block above for the full field list. * `sequence_fields` * Always present; `contact_replied` fires only for contacts in a sequence. * `contact_custom_fields` * Included when `includeProspectCustomFields: true`. *** ## Test webhook deliveries Once a webhook subscription is configured, you can send a test event to your endpoint: ```text theme={null} POST /v3/webhooks/{id}/test ``` The test payload matches the event schemas shown on this page and uses predictable placeholder values. # Webhook events Source: https://docs.reply.io/webhook-events All webhook events supported by the Reply API, grouped by category. This page lists all webhook event types supported by the Reply API. Each event links to its payload schema on the [Webhook event payloads](/webhook-event-payloads) page. To create or manage webhook subscriptions, see the [Webhooks API](/api-reference/webhooks/list-webhook-subscriptions). To retrieve supported event types programmatically, use the [List supported event types](/api-reference/webhooks/list-supported-event-types) endpoint. When [creating](/api-reference/webhooks/create-a-webhook-subscription) or [updating](/api-reference/webhooks/update-a-webhook-subscription) a subscription, pass the event name as the `eventType` value. ## Email engagement | Event | When it fires | Payload | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | | `email_sent` | Reply sends an email from a sequence step. | [View](/webhook-event-payloads#email_sent) | | `email_opened` | A recipient opens a tracked email. | [View](/webhook-event-payloads#email_opened) | | `email_link_clicked` | A recipient clicks a tracked link in an email. | [View](/webhook-event-payloads#email_link_clicked) | | `email_replied` | Reply detects an incoming reply to a sequence email, or a direct email reply not tied to a sequence. Fires once per detected reply. | [View](/webhook-event-payloads#email_replied) | | `reply_categorized` | An email reply is assigned a category automatically or by a user. | [View](/webhook-event-payloads#reply_categorized) | | `email_bounced` | A sent email bounces or is rejected by the recipient's mail server. | [View](/webhook-event-payloads#email_bounced) | | `email_auto_reply` | An incoming message is identified as an auto-reply or out-of-office message. | [View](/webhook-event-payloads#email_auto_reply) | ## Email account health | Event | When it fires | Payload | | ------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | | `email_account_connection_lost` | A connected mailbox can no longer authenticate, such as after an OAuth revocation or password change. | [View](/webhook-event-payloads#email_account_connection_lost) | | `email_account_error` | A mailbox reports an IMAP or SMTP error, such as an authentication failure, send failure, or rate limit. | [View](/webhook-event-payloads#email_account_error) | ## LinkedIn | Event | When it fires | Payload | | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | `linkedin_connection_request_sent` | Reply sends a LinkedIn connection request on behalf of a user. | [View](/webhook-event-payloads#linkedin_connection_request_sent) | | `linkedin_connection_request_accepted` | A previously sent LinkedIn connection request is accepted. | [View](/webhook-event-payloads#linkedin_connection_request_accepted) | | `linkedin_message_sent` | Reply sends a LinkedIn message or InMail. | [View](/webhook-event-payloads#linkedin_message_sent) | | `linkedin_message_replied` | A contact replies in a LinkedIn conversation. | [View](/webhook-event-payloads#linkedin_message_replied) | | `linkedin_reply_categorized` | A LinkedIn conversation is assigned a category. | [View](/webhook-event-payloads#linkedin_reply_categorized) | | `linkedin_account_alerts` | A LinkedIn account requires attention, such as a disconnected Sales Navigator account, usage limits, or low InMail credits. | [View](/webhook-event-payloads#linkedin_account_alerts) | ## Calls | Event | When it fires | Payload | | ---------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------- | | `contact_called` | A call with a contact reaches a final status, such as connected, missed, voicemail, or logged. | [View](/webhook-event-payloads#contact_called) | ## Contact lifecycle | Event | When it fires | Payload | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | | `contact_replied` | A contact enters the replied state — a reply is detected on any channel (email, LinkedIn, or SMS), or the contact is manually marked as replied. Channel-agnostic status signal. | [View](/webhook-event-payloads#contact_replied) | | `contact_finished` | A contact completes or exits a sequence. | [View](/webhook-event-payloads#contact_finished) | | `contact_opted_out` | A contact opts out through an unsubscribe link, manual action, or Do Not Contact setting. | [View](/webhook-event-payloads#contact_opted_out) | ## Sequence automation | Event | When it fires | Payload | | ------------------- | ---------------------------------------------- | ------------------------------------------------- | | `autopilot_stopped` | An evergreen sequence's autopilot is disabled. | [View](/webhook-event-payloads#autopilot_stopped) |