cherami.
API referenceSaved drafts

Create a draft

POST /v1/inboxes/{inbox_id}/drafts

Read as Markdown ↗

POST /v1/inboxes/{inbox_id}/drafts

Requires a Claim-issued API key: Authorization: Bearer YOUR_CREDENTIAL.

Drafts belong to one owned inbox. Saving or editing consumes no sending allowance and does not require sending permission. Sending requires current permission, recipient-policy approval and available allowance; deletion requires deletion permission.

The body can be {} for an empty draft. Supply any of to, cc, bcc, subject, text, html, attachments, in_reply_to and labels, using the sending field formats and limits. Recipients, subject and text may be missing or empty until sending. Unknown fields are rejected. Creation and edit JSON may be up to 8 MiB; saved content uses the same 5 MiB local bound, 50 recipients and 32 attachments as outgoing mail. Sending also checks current limits, including the provider's generated MIME limit.

html and in_reply_to additionally accept null to clear. Empty arrays clear recipient lists, attachments or initial sent-copy labels. Recipient display names are preserved. Supplied attachments are padded base64 original bytes, not URLs.

Optional idempotency_key protects creation. It accepts 1–128 ASCII letters, digits, hyphens or underscores. Keep it with the original payload and first request time; follow the creation-recovery guidance on this page.

New creation returns 201, Location: /v1/drafts/{id} and metadata.

The replayed and idempotency_expires_at fields appear only for keyed creation. Creation returns metadata, not the full body; retrieve the draft to inspect saved content.

Prepare a reply or forward

Creation also accepts source.

source.action is reply, reply-all or forward. message_id must identify a ready received or accepted sent message in the same inbox. The ordinary correspondence derivation rules apply: reply recipients exclude self and original Bcc; forwards retain original bodies rather than extracted reply text.

Replies save derived recipients, subject and in_reply_to, with your supplied response and new attachments. No original history or files are automatically copied. Explicit fields override derived fields, including empty arrays or a null reply target. The reply target must remain available and usable when the draft is sent; changing in_reply_to later does not rederive recipients or subject.

For forwards, text on creation is the introductory note. Supply recipients explicitly, or add them later. The saved text and HTML contain the full forward. source.include_attachments defaults to true and is valid only for forwards; false excludes all original files, including embedded images. Creation with a forward source cannot also supply attachments; edit afterward to replace the saved file list. Original bytes and usable inline Content-ID relationships are retained. Missing or oversized included files fail rather than being silently omitted. Forwarding does not redact private information already in the body.

Preparation happens once, before the draft is returned. Sending does not regenerate recipients, forward content or attachments from the source. A prepared forward remains usable if its source is subsequently deleted. A source is a preparation instruction on creation, not an editable field.

Recover creation

Creation keys are account-scoped across HTTP and MCP, in a namespace separate from inbox creation and sending. Protection lasts 24 hours from creation, without renewal. A matching retry returns 200, replayed: true and the original draft's current metadata, including later edits or submission state. It never reapplies the creation payload. A changed payload returns 409 idempotency_conflict.

The comparison uses normalized creation intent: omitted/empty arrays, trimmed display names, normalized label sets and missing/empty subject or text are equivalent. Content and recipient/file order remain significant. With a source, explicitly supplied fields are also significant because they override derived values; preserve the original payload. Default and explicit true attachment inclusion are equivalent.

Deleting the draft does not release an active key. A matching retry returns 409 idempotency_result_unavailable, without creating a replacement. Replay does not require reloading a preparation source that has since disappeared. Access and inbox ownership still apply.

If creation cannot be confirmed, retry only with the original key and payload within a conservatively measured 24 hours of the first request. Without a key or after expiry, list drafts with state=all and reconcile before creating anything else. Unlike an inbox address, draft content is not unique: blindly recreating can allocate a duplicate. A missing entry in one page does not establish that creation failed.

Parameters

ParameterLocationRequiredTypeMeaning
inbox_idpathYesstringOwned Cherami resource ID returned by the API.

Request body

JSON object. Total UTF-8 request body limit: 8388608 bytes.

Schema: CreateDraft

Incomplete content is allowed, including missing/empty recipients, subject and text. At most 50 combined recipients and 32 attachments; same local content bound as sending. With a forward source, attachments cannot also be supplied; text is the introductory note on creation only.

FieldRequiredTypeMeaning and constraints
toNoarray of MailboxmaxItems: 50
ccNoarray of MailboxmaxItems: 50
bccNoarray of MailboxmaxItems: 50
subjectNostringNo control characters; at most 998 UTF-8 bytes. x-max-utf8-bytes: 998
textNostringPlain-text body.
htmlNostring or null
attachmentsNoarray of AttachmentInput or nullOmitted or null means no attachments; an empty array also clears draft attachments.
in_reply_toNostring or null
labelsNoarray of LabelTrimmed, deduplicated and case-sensitive. Order is not significant. maxItems: 32
idempotency_keyNostringRetain a unique key, exact payload and first request time for this intended operation. Account-scoped protection lasts 24 hours without renewal. pattern: ^[A-Za-z0-9_-]{1,128}$
sourceNoobject or object

Unknown fields are rejected.

source fields

Exactly one of these shapes applies.

Alternative 1
FieldRequiredTypeMeaning and constraints
actionYes"reply" or "reply-all"
message_idYesstringReceived or accepted sent resource ID in this inbox. The source must have usable reply headers. pattern: ^[a-f0-9-]{36}$

Unknown fields are rejected.

Alternative 2
FieldRequiredTypeMeaning and constraints
actionYes"forward"
message_idYesstringReceived or accepted sent resource ID in this inbox. The source must have usable reply headers. pattern: ^[a-f0-9-]{36}$
include_attachmentsNobooleandefault: true

Unknown fields are rejected.

curl example

Replace resource-ID placeholders with returned IDs. Supply CHERAMI_API_KEY through your private shell environment.

Save the intended payload as a private request.json file and replace illustrative values. For an uncertain response, follow the operation-specific recovery rules.

{
  "subject": "Proposal for review",
  "text": "Draft proposal.",
  "idempotency_key": "RETAIN_A_UNIQUE_CREATION_KEY"
}
curl --silent --show-error --include --request POST \
  "https://cherami.to/v1/inboxes/INBOX_ID/drafts" \
  --header "Authorization: Bearer $CHERAMI_API_KEY" \
  --header 'Content-Type: application/json' \
  --data-binary @request.json

Responses

HTTP 200

Matching replay: current resource or saved attempt, without another allocation or provider submission.

  • X-Request-ID: Support correlation ID, not an idempotency key.
  • Location: Relative URL of the resulting resource.

Content type: application/json.

All of these schemas apply.

Part 1

CreatedDraft

Part 2

FieldRequiredTypeMeaning and constraints
replayedYestrue
idempotency_expires_atYesstringUTC service instant with milliseconds and Z suffix. format: date-time pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$
{
  "id": "11111111-1111-4111-8111-111111111111",
  "inbox_id": "11111111-1111-4111-8111-111111111111",
  "state": "draft",
  "subject": "Example",
  "created_at": "2026-10-01T00:00:00.000Z",
  "updated_at": "2026-10-01T00:00:00.000Z",
  "sent_message_id": null,
  "replayed": true,
  "idempotency_expires_at": "2026-10-02T00:00:00.000Z"
}

HTTP 201

Successful operation; inspect resource state and outcome fields.

  • X-Request-ID: Support correlation ID, not an idempotency key.
  • Location: Relative URL of the resulting resource.

Content type: application/json.

All of these schemas apply.

Part 1

CreatedDraft

Part 2

FieldRequiredTypeMeaning and constraints
replayedNofalse

HTTP 400

invalid_json: Send a valid UTF-8 JSON object, not an array or scalar.

invalid_draft: Use supported draft fields, source preparation or listing parameters. Draft cursors that are malformed or do not match the inbox/state also use this code.

invalid_message: Correct the send fields, recipients, reply ID, or attachments using the message's guidance.

invalid_name: Correct the inbox, sender or recipient display name using the returned guidance.

invalid_labels: Correct label names, changes, filter groups, or discovery prefix.

invalid_idempotency_key: Use 1–128 ASCII letters, digits, hyphens or underscores.

  • X-Request-ID: Support correlation ID, not an idempotency key.

Content type: application/json.

Error

HTTP 401

unauthorized: Provide a valid bearer credential. Use human-approved recovery if access is lost.

  • X-Request-ID: Support correlation ID, not an idempotency key.
  • WWW-Authenticate: "Bearer"

Content type: application/json.

Error

HTTP 404

not_found: Resource is absent or inaccessible to this account. Reply targets must be in the sending inbox.

  • X-Request-ID: Support correlation ID, not an idempotency key.

Content type: application/json.

Error

HTTP 409

idempotency_conflict: The key belongs to different input. Recover with the original inbox and payload, not a replacement key.

idempotency_result_unavailable: The key was used but its inbox, draft or sent copy is unavailable. No replacement was created or submitted; do not bypass protection with a new key.

reply_not_ready: A received reply or forward source must be ready; a sent source must have confirmed provider acceptance.

reply_recipients_unavailable: No other visible reply recipients remain after self-exclusion. Use explicit send with human-authorized recipients.

  • X-Request-ID: Support correlation ID, not an idempotency key.

Content type: application/json.

Error

HTTP 413

body_too_large: Reduce the JSON request to the endpoint's body limit.

message_too_large: Reduce message content and attachments. Passing local checks does not guarantee generated MIME fits the provider limit.

  • X-Request-ID: Support correlation ID, not an idempotency key.

Content type: application/json.

Error

HTTP 415

unsupported_media_type: Send Content-Type: application/json.

  • X-Request-ID: Support correlation ID, not an idempotency key.

Content type: application/json.

Error

HTTP 503

content_unavailable: Expected stored content is unavailable. Retry the read later.

draft_unavailable: Draft operation is uncertain. Follow draft-specific recovery; do not blindly create a replacement.

  • X-Request-ID: Support correlation ID, not an idempotency key.

Content type: application/json.

Error

Schema: CreatedDraft

FieldRequiredTypeMeaning and constraints
idYesstringCherami resource ID, distinct from the RFC Message-ID. Use the returned value.
inbox_idYesstringCherami resource ID, distinct from the RFC Message-ID. Use the returned value.
stateYes"draft" or "submitted"
subjectYesstring
created_atYesstringUTC service instant with milliseconds and Z suffix. format: date-time pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$
updated_atYesstringUTC service instant with milliseconds and Z suffix. format: date-time pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$
sent_message_idYesstring or null
replayedNoboolean
idempotency_expires_atNostringUTC service instant with milliseconds and Z suffix. format: date-time pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$

Schema: Error

FieldRequiredTypeMeaning and constraints
errorYesobject

error fields

FieldRequiredTypeMeaning and constraints
codeYesstringProgrammatic error code. Handle unrecognized codes by status and operation-specific recovery.
messageYesstringHuman-readable context, not a stable string to match.

Schema: Mailbox

FieldRequiredTypeMeaning and constraints
addressYesstringBare ASCII address, at most 254 characters, local part at most 64. No display-name header syntax. maxLength: 254
nameNostringUnicode name, trimmed; blank means unnamed. No control characters. At most 256 UTF-8 bytes after trimming. x-max-utf8-bytes: 256

Unknown fields are rejected.

Schema: AttachmentInput

FieldRequiredTypeMeaning and constraints
filenameYesstringNonempty, no control characters, slash or backslash. At most 255 UTF-8 bytes. minLength: 1 x-max-utf8-bytes: 255
typeYesstringMIME type without parameters. maxLength: 127 pattern: ^[A-Za-z0-9!#$&^_.+-]+/[A-Za-z0-9!#$&^_.+-]+$
contentYesstringPadded base64 original bytes, no whitespace; encoded length must be a multiple of four. Empty files are accepted. contentEncoding: base64 pattern: ^[A-Za-z0-9+/]*={0,2}$

Unknown fields are rejected.

Schema: Label

1–128 UTF-8 bytes after trimming. Well-formed Unicode without control characters; case-sensitive.

string. x-max-utf8-bytes: 128

HTTP conventions, errors and pagination · Download OpenAPI 3.1

On this page