Getting Started

Authentication, ids, errors, writing email copy, webhooks, and the MCP server.

1Pick a language

2Credentials

3Try It!

LoadingLoading…
Response
Click Try It! to start a request and see the response here!

REST API for the Sender Pools platform.

Authentication

Every request is authenticated with an API key passed as a bearer token: Authorization: Bearer apiKey.... Create and revoke keys in the dashboard under Settings > API Keys.

Identifiers

Most paths are scoped by two ids you can copy from Settings > Workspaces:

  • accountId: your account, prefixed account_.
  • workspaceId: the workspace the data belongs to. Read endpoints that list across a whole
    account also accept the literal value all.

Errors

Errors are returned as JSON with a message or error field. 403 means the key is missing, revoked, or lacks permission for that resource; 404 means the resource does not exist in your account; 400 carries an errors array describing which fields failed validation.

Writing email copy

A TEMPLATE sequence step sends an email template you write: one subject and body, sent to every prospect at that step and personalised for each of them. Create it with Create Email Template.

To A/B test a step, give it two or more email templates. Sends are split between the active templates at random, the templates are labelled A, B and so on, and Get Template Metrics compares their reply rates.

A template's copy is written as subjectText and bodyText, plain text with two kinds of token in it:

{Hi|Hey|Hello} {{firstName??there}}, saw {{Industry}} is hiring.
  • {{firstName}} inserts a field, and ?? gives it a fallback for when that field is
    empty. Without a fallback an empty field leaves nothing.

  • {a|b|c} is spintax: one option is picked at random for each email. A {word} with no
    | is left alone as ordinary text.

Fields may be named however you like: {{firstName}}, {{First Name}} and {{FIRST_NAME}} all resolve, and a custom field is referenced by its name rather than its id. The available fields are firstName, lastName, title, email, companyName and companyDomain, plus every custom field in the workspace, plus senderFirstName, senderLastName and senderSignature, which come from the sending mailbox at send time and so stay unresolved in a preview. senderSignature works in the body only.

A token naming no known field is rejected, so a typo is an error rather than a blank space in a sent email. Spintax does not nest, and a token inside a spintax option takes no fallback. Both forms work in the subject as well as the body, and Preview Email Copy renders either against a real prospect before you commit to it.

Get Sequence Step returns the same shorthand as subjectText and bodyText, so copy reads back in the form it was written and can be edited and sent straight back.

Writing copy does not rewrite the emails already queued against your prospects. Finish editing a step, then call Rebuild Step Emails once for it, and the queued emails are regenerated from the current copy. Emails already sent are never touched.

subject and body are the same copy as the dashboard editor's HTML. They are what the dashboard writes, and you may send them instead, but nothing needs to: shorthand is the supported way in through the API. Send one form or the other, never both.

AI copy and pitch configs

An AI sequence step has Sender Pools write a different email for every prospect. Two things shape that copy: the ICP's positioning (description, problem, solution, statusQuo, competitiveAdvantage and concerns, set with Create ICP and Update ICP) and the ICP's pitch config.

A pitch config picks the angles the copy is written from: one or more copy frameworks (such as PAS, Problem, Agitation, Solution), one or more tones, the trigger reasons for reaching out, and a goal, the call to action the email asks for. Every combination of trigger reason, framework and tone is a pitch. Each prospect's first email is written from one pitch picked at random, and that prospect's follow-ups keep using it, so a config with three frameworks and two tones spreads your prospects across six pitches.

You do not have to set one. When an ICP gets an AI step and has no pitch config, Sender Pools gives it the same defaults as the dashboard's "Pick for me" button: the AIDA, PAS and HEART frameworks, an informal and direct tone, the Cold Contact trigger and the schedule_call goal. Call Set Pitch Config to choose your own, and List Pitch Goals for the goals you can use. Get ICP returns the current config as pitchConfig.

Changing the pitch config does not rewrite the emails already queued. It marks every unsent AI email written from a replaced pitch for regeneration; call Rebuild Step Emails for each AI step to carry it out. Emails already sent are never touched, and a prospect whose first email has already been sent keeps its original pitch for the rest of the sequence.

Positioning and the pitch config apply to the whole ICP. When one step needs guidance of its own, give it step context: notes (an offer specific to that step, a local detail, a claim to avoid) and example emails the AI writes in the style of. Get Step Context reads it and Set Step Context replaces it. Like a pitch change, saving context marks that step's unsent AI emails for regeneration; call Rebuild Step Emails for the step to carry it out.

Per-contact copy

A PER_CONTACT sequence step sends copy you write for each prospect instead of one template for everyone. Supply it on Import Contacts as emails on each contact, where emails[0] is the first email of the sequence, emails[1] the second, and so on. The copy uses the same shorthand as above, so {{firstName??there}} and {a|b} work in it, and it is rendered against that prospect when the email is built.

When an ICP has a PER_CONTACT step, every contact on an API import must have copy for it: a body, plus a subject when the step is the first email. A contact already in the ICP may rely on copy it was imported with before. An import with a contact missing it is rejected with a 400 naming the contacts, and nothing is imported.

Importing a contact that is already in the ICP updates its copy. Emails that have not been sent yet are rebuilt from the new copy straight away; emails already sent, or sending, keep the copy they went out with. A field you leave out keeps the copy already stored, and stored copy counts towards the requirement above, so a re-import can carry only what changed.

To read or change one prospect's copy, use Get Prospect Email Copy and Update Prospect Email Copy. The copy comes back as the shorthand you wrote, alongside the email it builds for that prospect, so you can check the result before it sends. Preview Email Copy is different: it renders copy you have not saved yet against one of the ICP's prospects, not one you choose, which suits checking the shorthand is well formed before an import.

Webhook deliveries

Subscribed events are delivered as POST requests with this body:

{
  "id": "8f1c...",
  "type": "NEW_REPLY",
  "workspaceId": "...",
  "occurredAt": "2026-09-14T18:04:11.204Z",
  "data": { }
}

data holds the event payload: workspace, account, icp, contact, icpContactId and email for the email events, or contact, icpContactId and a leadResponse {old, new} pair for LEAD_RESPONSE_UPDATED. Test events additionally carry "test": true.

An email event carries everything needed to act on the reply without a further lookup: email.threadId for Get Inbox Thread, email.mailboxId and email.messageId for the fromMailboxId and inReplyToId of Reply To A Thread, and icpContactId for the prospect itself.

Three headers accompany every delivery:

  • X-Senderpools-Signature: sha256=<hex>, an HMAC-SHA256 of the raw request body
    keyed with the endpoint's signingSecret. Compare it with a constant-time comparison.

  • X-Senderpools-Event: the event type.

  • X-Senderpools-Delivery: the event id, identical to id in the body.

Deliveries time out and are retried, so the same event id can arrive more than once. Key your handler on id and make it idempotent. Return any 2xx to acknowledge; anything else is recorded as a failure and retried.

MCP server

Every endpoint in this reference is also available to AI assistants over the Model Context Protocol, at

https://api.senderpools.com/api/mcp

It is a Streamable HTTP MCP server authenticated with the same API key, sent the same way: Authorization: Bearer apiKey.... There is one tool per operation documented here, named after its summary (list_workspaces, import_contacts, list_inbox_threads, reply_to_thread, ...), and a key reaches exactly the same data through MCP as it does through REST.

You never pass an accountId to a tool: the key identifies the account. Most tools take a workspaceId, which list_workspaces returns.

In Claude Code:

claude mcp add --transport http senderpools https://api.senderpools.com/api/mcp \
  --header "Authorization: Bearer apiKey..."

In a client configured with JSON, such as Claude Desktop or Cursor:

{
  "mcpServers": {
    "senderpools": {
      "type": "http",
      "url": "https://api.senderpools.com/api/mcp",
      "headers": {"Authorization": "Bearer apiKey..."}
    }
  }
}
Popular Endpoints
Last 24 Hours
LoadingLoading…

Did this page help you?