Idempotency-Key for each intended email, SMS/MMS, or iMessage. Reuse that
key and the same input if the request times out. Use a new key for a deliberately
new message, even if its content is identical.
For raw HTTP requests, also send Prefer: idempotency-replay to select the replay
contract below. SDKs and CLI version 0.7.10 send this preference automatically.
Requests without this preference keep their existing behavior: completed keyed
email retries return 409, and SMS/iMessage calls are independent sends.
Email and SMS still wait for send acceptance before returning success. iMessage
keeps its existing queued acknowledgement. Response shapes and delivery fields are unchanged.
The SDKs generate a key for each send call and preserve it during bounded request
retries. Pass an explicit key for a workflow that retries across separate calls or
processes. The CLI exposes --idempotency-key on email, text, and iMessage sends.
Retry outcomes
Recorded responses include
Preference-Applied: idempotency-replay.
Idempotency-Rejected: true means the original request was definitively rejected
without sending. After correcting that issue, you may explicitly start a new
attempt with a new key. Do not infer this from HTTP status alone: a conflict or
missing result can refer to a message that was already sent.
This includes recorded pre-send iMessage rejections. Authentication or validation
failures that cannot establish the original request’s outcome may omit the header.
Keys must be nonblank, contain 1–255 printable ASCII characters, and have a seven-day supported
response-replay window. Do not intentionally reuse a key for another message.
Keys are scoped to your organization, sending resource, and operation.
An expired key cannot start a new message; its original response is unavailable.
A replay is the original request result, not current delivery tracking. Use the
message’s normal get endpoint or delivery webhooks for live status. A successful
queued response does not mean the recipient has received the message. Request
retries do not guarantee delivery retries. A missing delivery receipt does not
justify creating a second message.
For 503 send_outcome_ambiguous, respect Retry-After before checking again with
the same key. Lookup or outbound history may help, but an interrupted email/SMS
request may have no recoverable message ID and can remain unresolved. Never
automatically switch keys because a lookup returned 404.
Recover the original message ID
Supply the original key in the
Idempotency-Key header, together with your usual
authentication. This read-only endpoint does not send or resume a message.
404 means no result is available to you. It does not prove the message was never
sent: the original request may still be processing. Do not generate a new key
automatically after a missing lookup result.
Lookup can return 403 when your credential is not allowed to use the selected
channel, or 422 for a missing/invalid key, UUID, sender kind, or operation.
An email-address helper resolves the mailbox UUID before performing lookup.
An interrupted email or SMS send may remain unconfirmed without a message ID.
Reusing its key does not submit another message. After a confirmed rejection that
permits retry, the eventual message ID may differ and the email may use your updated mailbox signature
from the earlier unsuccessful attempt. Once a final response is available, replays
return that original response.
Keep the key after an error
Python exposesget_message_request_key(error) from inkbox; TypeScript exposes
getMessageRequestKey(error) from @inkbox/sdk. These recover the generated key
from send errors, including transport failures. The CLI prints it in stderr and
includes error.idempotencyKey with --json.
Rust errors do not expose generated keys. Preserve your own key and use an
explicit-key send method when you need to retry or look up the request across calls.
Use imessages.get(message_id) in Python, imessages.get(messageId) in TypeScript,
or inkbox imessage get <message-id> --identity <handle> to read a recovered iMessage.

