Avoiding duplicate sends

Operations

What to do when your agent retries a send and you're not sure whether the first one went through.

The scenario

Agent calls POST /send. The response times out. Did the message go or not? Naive retry risks sending twice.

Use an Idempotency-Key

Every send endpoint accepts an Idempotency-Key header: /send, /reply/{messageId}, /reply-all/{messageId}, /forward/{messageId} and /drafts/{draftId}/send. Generate a unique value (a UUID works) once per intended send, and reuse it on every retry of that send.

curl -X POST https://anjal.app/v1/inboxes/$ID/send \
  -H "X-API-Key: ak_..." -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2a4e-9b1d-4c1e-8f3a-2d9e7b5c0a11" \
  -d '{"to": "lead@acme.com", "subject": "Hi", "plainBody": "...", "verified": true}'
  • Same key, identical request: you get the stored response of the first send, with the header Idempotent-Replayed: true. Nothing is sent again.
  • Same key, different request (body, inbox or endpoint): 409 IDEMPOTENCY_KEY_REUSED.
  • Same key while the first request is still running: 409 IDEMPOTENCY_IN_PROGRESS. Wait a moment and retry with the same key.
  • Header present but blank (or over 255 characters): 400 IDEMPOTENCY_KEY_INVALID.
  • The first send failed (any non-2xx): the key is freed, so a retry with the same key sends normally.

Keys are scoped to your account and expire after 24 hours. MCP send tools take the same value as an idempotencyKey argument.

Without a key

  • If a POST /send call times out or returns a 5xx and you sent no key, don't retry immediately. List recent outbound messages (?direction=outbound&limit=10) and look for a matching subject and to first.
  • Drafts are another safe staging step: the second POST /drafts/{id}/send call returns a 404 because the first one deleted the draft.