BitelioBitelio

Idempotency

Attach an Idempotency-Key header so retries and double-submits can never trigger the same send or event twice

Retry a request and you've sent the same email twice. Let a checkout form double-submit and the customer gets two receipts. The fix is the Idempotency-Key header, which guarantees a request runs at most once.

When Bitelio sees a key for the first time, the request goes through as usual. When the same key shows up again within your project, the request is refused with a 409 instead of being executed a second time.

The header is supported on both public API write endpoints:

  • POST /v1/track
  • POST /v1/send

Sending a key

Any string of 1–255 printable ASCII characters works as a key. What matters is that each logical operation gets its own — either a UUID, or something you derive from your own records, such as receipt-order-1234.

curl -X POST https://api.bitelio.com/v1/send \
  -H "Authorization: Bearer sk_your_secret_key" \
  -H "Idempotency-Key: receipt-order-1234" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "customer@example.com",
    "subject": "Your receipt",
    "body": "<p>Thanks for your order!</p>"
  }'
await fetch('https://api.bitelio.com/v1/send', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer sk_your_secret_key',
    'Idempotency-Key': 'receipt-order-1234',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    to: 'customer@example.com',
    subject: 'Your receipt',
    body: '<p>Thanks for your order!</p>',
  }),
});
import requests

requests.post(
    "https://api.bitelio.com/v1/send",
    headers={
        "Authorization": "Bearer sk_your_secret_key",
        "Idempotency-Key": "receipt-order-1234",
    },
    json={
        "to": "customer@example.com",
        "subject": "Your receipt",
        "body": "<p>Thanks for your order!</p>",
    },
)

What happens on reuse

A repeated key comes back as a 409 carrying the error code IDEMPOTENCY_KEY_REUSED. Inside details you'll find information about the request that claimed the key first:

{
  "success": false,
  "error": {
    "code": "IDEMPOTENCY_KEY_REUSED",
    "message": "Idempotency-Key \"receipt-order-1234\" has already been used",
    "statusCode": 409,
    "details": {
      "key": "receipt-order-1234",
      "originalRequest": "POST /v1/send",
      "originalRequestAt": "2025-01-15T10:30:00.000Z",
      "originalStatusCode": 200
    }
  }
}

If originalStatusCode is null, the first request hasn't finished yet — both requests carrying the key arrived simultaneously and this one lost the race.

On a reused key, Bitelio refuses — it does not replay the first response. The 409 guarantees nothing ran twice, but it won't hand you the original email or event ID. Capture that ID yourself when the first request succeeds if you'll need it later.

Which failures free the key

A failed request doesn't always consume the key.

Outcome of the first requestKey isWhy
2xx successKeptThe operation happened. A retry would duplicate it.
4xx client errorReleasedValidation and permission failures are rejected before any write occurs, so correcting the request and retrying under the same key is safe.
5xx server errorKeptPart of the work may already have happened. Blocking the retry is exactly what the key is for.

If a 5xx consumed a key but you're certain the operation never took effect, retry under a fresh key.

Scope and expiry

A key belongs to your project as a whole, not to a single endpoint — once spent on /v1/track, it can't be replayed against /v1/send. Separate projects, on the other hand, can each use the same key string without interfering.

Claimed keys expire after 24 hours and can be used again from that point.

Multiple recipients

When you pass an array of recipients to POST /v1/send, they're processed sequentially — but the idempotency key protects the request as a unit, not recipient by recipient. Should the request die partway with a 5xx, some recipients may already have received their email; the key stays claimed for exactly that reason, so a naive retry can't hit them twice.

If you need control at the recipient level, issue one request per recipient, each carrying its own key.