Skip to main content
Sending is one endpoint, two modes:
  • New conversation — pass to, subject, and a body. We pick a mailbox from the pool, register the conversation, fire email.sent.
  • Reply to existing — pass convId and a body. We resolve recipient, subject, threading headers, and the bound mailbox from the conv.
POST /v1/identities/:handle/send

New conversation

curl https://api.inboxbase.ai/v1/identities/alice.acme@inboxbase.ai/send \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to":      "morgan@northwindrobotics.com",
    "subject": "Quick intro — fleet rotation",
    "text":    "Hi Morgan, ...",
    "html":    "<p>Hi Morgan, ...</p>"
  }'
text and html can both be set; recipients see the multipart message their client prefers. Most production senders set both. If you’re stitching to a thread that started outside 12m (e.g. you imported a CRM history), pass inReplyTo and references:
{
  "to":         "morgan@northwindrobotics.com",
  "subject":    "Re: Fleet rotation",
  "text":      "Following up...",
  "inReplyTo": "<original-message-id@northwindrobotics.com>",
  "references": ["<original-message-id@northwindrobotics.com>"]
}

Reply to a thread

When you have the convId from a prior send (or from a webhook), replying is one field:
curl https://api.inboxbase.ai/v1/identities/alice.acme@inboxbase.ai/send \
  -H "Authorization: Bearer sk_live_..." \
  -d '{
    "convId": "conv_dd6e7130674645d3",
    "text":   "Friday at 10 works."
  }'
We pull recipient, subject (with the Re: prefix), threading headers, and — critically — the same backing mailbox from the conversation state. Recipients see a coherent thread from one consistent sender. convId is mutually exclusive with to / subject. Cross-identity replies (a convId that lives on a different identity) return 404.

Idempotency

Every send accepts an optional Idempotency-Key header. Same key with the same body returns the original response (with Idempotent-Replayed: true); same key with a different body returns 409. Keys live for 24 hours.
curl https://api.inboxbase.ai/v1/identities/alice.acme@inboxbase.ai/send \
  -H "Authorization: Bearer sk_live_..." \
  -H "Idempotency-Key: 9b3e84c2-7c0b-4f9c-8cb2-..." \
  -d '{ "to": "morgan@...", "subject": "Hi", "text": "..." }'
For sequencers, the right key is <leadId>:<step> — if the worker crashes after we accepted the send but before your DB recorded it, the retry returns the same response and you don’t double-send.

Response

{
  "accepted":  1,
  "rejected":  0,
  "remaining": 49,
  "dailyCap":  150,
  "identity":  "alice.acme@inboxbase.ai",
  "messages": [
    {
      "to":       "morgan@northwindrobotics.com",
      "id":       "<provider-message-id>",
      "status":   "accepted",
      "convId":   "conv_dd6e7130674645d3",
      "affinity": "new",
      "account":  { "id": "acc_...", "email": "alice.chen@tryacme.com" }
    }
  ]
}
The fields worth knowing:
  • convId — store this against your lead/contact record. Every follow-up uses it.
  • affinitynew (we created an affinity row), existing (we reused the recipient’s pinned mailbox), or reassigned (the pinned mailbox was unhealthy or capped, we picked another).
  • account.email — the rotated mailbox we used. Surfaced for transparency and deliverability dashboards. You don’t need to act on it.
  • remaining — daily-cap budget left on this identity today.
Status code: 202 if anything was accepted, 429 if every recipient was rejected (typically cap_exceeded).

What we don’t support yet

In the interest of not lying to you:
  • Scheduled sends. No sendAt. Every send dispatches immediately. If you need “fire at 9am Tuesday in the prospect’s timezone,” run a scheduler in your own infra and call us at fire time. The Idempotency-Key makes the retry semantics safe.
  • Attachments. Not supported. If your use case needs them, tell us.
  • Custom headers. No way to set List-Unsubscribe / List-Unsubscribe-Post today. This is high-priority because Gmail/Yahoo bulk-sender requirements increasingly need it; we’ll ship it.
  • Multi-recipient sends. to accepts an array, but we send to each recipient separately so each gets its own conversation. Bulk broadcasts to cc lists aren’t a 12m use case — that’s transactional email territory.