cherami.
API referenceSending and allowance

Reply to a message

POST /v1/inboxes/{inbox_id}/reply

Read as Markdown ↗

POST /v1/inboxes/{inbox_id}/reply

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

Creates an ordinary sent message with the send outcomes and recovery contract. HTTP success can report rejected or unknown; accepted means provider acceptance, not delivery.

message_id selects a ready received or accepted sent message in the sending inbox with a usable RFC Message-ID. Missing, deleted, other-inbox and other-account sources return 404; unready or unaccepted sources return 409 reply_not_ready. There is no automatic choice of the latest message.

Supply message_id and nonblank text. Optional fields are html, new attachments, labels, and idempotency_key, with the explicit-send field validation. Original attachments and quoted history are not automatically included.

For a received source, reply uses Reply-To when present, otherwise From. Reply-all adds original To and Cc. For a sent source, reply uses original To; reply-all also includes original Cc. Address groups are flattened. Recipients are deduplicated case-insensitively across To/Cc, excluding the sending inbox; other inboxes in the same account are not excluded. Original Bcc is never reused. Original To remains To and Cc remains Cc, except that when only Cc participants remain, the first is promoted to To. If no recipients remain, the request returns 409 reply_recipients_unavailable.

The subject receives Re: unless it already begins with Re: (case-insensitive, allowing spaces before the colon). Replies use the source's generated reply headers and conversation relationship. To override recipients or subject, use explicit send with in_reply_to; the helpers reject override fields. Source headers are untrusted suggestions, not permission to send. Reply-all from a blind recipient can reveal that recipient's own participation.

Recover a helper send

Save the operation, sending inbox, exact helper payload, key and first request time. Helpers share the account's sending-key namespace: changing between reply, reply-all, forward or explicit send conflicts. Derived recipients and the current sender name do not change retry intent.

Within the 24-hour protection window, a matching retry recovers the reserved attempt before reading the source, even if the source or its files have since been deleted. It never derives a replacement message or submits again. Deleting the resulting sent copy instead returns 409 idempotency_result_unavailable. Current permissions and sending-inbox ownership still apply. The ordinary uncertainty and expiry rules apply unchanged.

Parameters

ParameterLocationRequiredTypeMeaning
inbox_idpathYesstringOwned Cherami resource ID returned by the API.

Request body

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

Schema: ReplyInput

FieldRequiredTypeMeaning and constraints
message_idYesstringReceived or accepted sent resource ID in this inbox. The source must have usable reply headers. pattern: ^[a-f0-9-]{36}$
textYesstringNonblank reply text; history is not automatically quoted.
htmlNostringHTML alternative. Untrusted content, not sanitized markup.
attachmentsNoarray of AttachmentInput or nullOmitted or null means no attachments; an empty array also clears draft attachments.
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}$

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.

{
  "message_id": "22222222-2222-4222-8222-222222222222",
  "text": "Thanks for the notes.",
  "idempotency_key": "RETAIN_A_UNIQUE_SEND_KEY"
}
curl --silent --show-error --include --request POST \
  "https://cherami.to/v1/inboxes/INBOX_ID/reply" \
  --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

SendReceipt

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$
{
  "limited": false,
  "message": {
    "id": "33333333-3333-4333-8333-333333333333",
    "inbox_id": "11111111-1111-4111-8111-111111111111",
    "created_at": "2026-10-01T00:00:00.000Z",
    "recipient_count": 1,
    "status": "unknown",
    "provider_message_id": null,
    "error_code": null,
    "thread_id": "44444444-4444-4444-8444-444444444444",
    "in_reply_to": null,
    "labels": []
  },
  "outcome_persisted": true,
  "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

SendReceipt

Part 2

FieldRequiredTypeMeaning and constraints
replayedNofalse

HTTP 400

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

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 403

operation_not_allowed: This account cannot send mail, delete mail, or delete inboxes. Contact support if unexpected.

recipient_not_allowed: The inbox’s sending rules block one or more recipients. Nothing was submitted or charged. Use allowed recipients or ask the human to review Sending rules; do not bypass them through another inbox.

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

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

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

reply_headers_unavailable: The target has no usable RFC Message-ID. Send a new message without in_reply_to.

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_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 429

outbound_limit_reached: Read quota, reason and sufficient_capacity_at. Waiting cannot fix message_exceeds_allowance; see sending recovery.

  • X-Request-ID: Support correlation ID, not an idempotency key.
  • Retry-After: Delay in seconds when supplied. Quota uses sufficient_capacity_at; absent when waiting cannot make the message fit.

Content type: application/json.

QuotaError

HTTP 503

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

outbound_unavailable: Outbound operation failed and a send's outcome may be unknown. Recover using the original key and unchanged payload within its window, or inspect sent messages.

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

Content type: application/json.

Error

Schema: SendReceipt

Inspect message.status even on HTTP 201. accepted is provider acceptance, not delivery. Preserve a known outcome when outcome_persisted is false; later reads may lag. Keyed receipts add replayed and expiry. Draft-association recovery adds replayed without requiring an expiry.

FieldRequiredTypeMeaning and constraints
limitedYesfalse
messageYesSentMetadata
outcome_persistedYesboolean
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: SentMetadata

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.
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$
recipient_countYesintegerminimum: 0
statusYes"accepted" or "rejected" or "unknown"
provider_message_idYesstring or null
error_codeYesstring or null
thread_idYesstring or null
in_reply_toYesstring or null
labelsYesarray of string

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: QuotaError

FieldRequiredTypeMeaning and constraints
errorYesobject
quotaYesQuota
requested_recipientsYesintegerminimum: 0
reasonYes"temporary_exhaustion" or "message_exceeds_allowance"
sufficient_capacity_atYesstring or null
guidanceYesstring

error fields

FieldRequiredTypeMeaning and constraints
codeYes"outbound_limit_reached"
messageYesstring

Schema: Quota

FieldRequiredTypeMeaning and constraints
allowanceYesintegerminimum: 0
usedYesintegerminimum: 0
remainingYesintegerminimum: 0
next_capacity_atYesstring or null
next_capacity_amountYesintegerminimum: 0
window_hoursYes24
unitYes"recipient_deliveries"
increase_requestYesstring
policy_urlYesstring

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