Every object the Dairo API sends and receives, with its fields.
The objects of the API, generated from the published OpenAPI document at docs.dairo.app/openapi.json. Fields marked as required are always present in responses and must be sent in requests.
The resolved ACTIVE organization for the request and the caller's role in it.
| Field | Type | Required | Description |
|---|
id | string or null | yes | |
role | string or null | yes | |
Provide an apiKeyId and/or inboxId to bind to this agent.
| Field | Type | Required | Description |
|---|
apiKeyId | string or null | no | |
inboxId | string or null | no | |
| Field | Type | Required | Description |
|---|
agentId | string | yes | |
apiKeyId | string or null | no | |
inboxId | string or null | no | |
bound | boolean | yes | |
| Field | Type | Required | Description |
|---|
display | string | yes | Human-readable agent name. (max length 120) |
description | string or null | no | |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
agentId | string | yes | Portable, durable public identifier (agt_...). |
display | string | yes | |
description | string or null | no | |
status | "active", "suspended", "revoked" | yes | |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes | |
An agent's rolling reputation and circuit-breaker state.
| Field | Type | Required | Description |
|---|
agentId | string | yes | |
state | "healthy", "throttled", "quarantined", "review" | yes | Circuit-breaker state. healthy sends freely; throttled sends under a reduced per-agent rate; quarantined is fail-closed (no send) until cleared; review is an operator-pinned hold. |
verdict | "allow", "throttle", "block", "review" | yes | |
shouldSend | boolean | yes | false only when the agent is quarantined. Poll before a batch. |
window | object | yes | |
rates | object | yes | |
thresholds | object | yes | |
lastReason | string or null | no | |
lastTrippedAt | string or null | no | |
lastEvaluatedAt | string or null | no | |
overrideLocked | boolean | no | |
| Field | Type | Required | Description |
|---|
agentId | string | yes | |
state | string | yes | |
overrideLocked | boolean | no | |
shouldSend | boolean | yes | |
reputation | object or null | no | |
| Field | Type | Required | Description |
|---|
window | object | no | |
thresholds | object | no | |
agents | array of object | yes | |
| Field | Type | Required | Description |
|---|
object | "api_key" | yes | |
id | string (uuid) | yes | |
name | string | yes | |
prefix | string | yes | |
scopes | array of string | yes | |
status | "active", "revoked" | yes | |
createdAt | string (date-time) | yes | |
lastUsedAt | string (date-time) or null | no | |
allowedIps | array of string or null | no | The key's IP allowlist (IPv4/IPv6 addresses or CIDR ranges), or null when the key authenticates from any IP. |
inboxIds | array of string (uuid) or null | no | The inbox ids (inboxes.id) this key may send as. Empty or null means the key is unrestricted and may send as any inbox in the project — the default, and what every key minted before this field existed has. |
environment | "live", "test" | no | |
| Field | Type | Required | Description |
|---|
apiKeys | array of ApiKey | yes | |
| Field | Type | Required | Description |
|---|
attachment | MessageAttachment | yes | |
downloadUrl | string (uri) | yes | |
expiresInSeconds | integer | yes | (minimum 1, maximum 604800) |
shareUrl | string (uri) | yes | Human branded Dairo share page URL for the attachment. |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
name | string | yes | |
description | string or null | no | |
status | string | yes | |
memberCount | integer or null | no | |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
name | string | yes | (min length 1) |
description | string | no | |
| Field | Type | Required | Description |
|---|
deleted | boolean | yes | |
id | string (uuid) | yes | |
| Field | Type | Required | Description |
|---|
audiences | array of Audience | yes | |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
audienceId | string (uuid) | yes | |
email | string (email) | yes | |
contactId | string (uuid) or null | no | Set when this member was added as a contact (§12); the email is derived from the contact's primary email handle. Null for a raw-email member. |
name | string or null | no | |
metadata | object | yes | |
status | string | yes | |
source | string | yes | |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
members | array of object | yes | (min items 1, max items 2000) |
| Field | Type | Required | Description |
|---|
audienceId | string (uuid) | yes | |
imported | integer | yes | |
| Field | Type | Required | Description |
|---|
list | Audience | yes | |
Signed manifest committing to the export window bounds, rowCount, and chain head.
Type: SignedArtifact and object.
A hash-chained audit-ledger export plus its signed verification manifest.
| Field | Type | Required | Description |
|---|
rows | array of AuditExportRow | yes | |
manifest | AuditExportManifest | yes | |
pagination | object | no | Keyset pagination for draining history past the 5000-row page cap. |
One hash-chained audit row in an export.
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
userId | string (uuid) | yes | |
action | string | yes | |
resourceType | string or null | no | |
resourceId | string or null | no | |
metadata | object | no | |
actor | string or null | no | |
ip | string or null | no | |
agentId | string or null | no | |
chainSeq | integer or null | yes | 1-based contiguous per-user sequence; a gap means a deleted row. |
prevHash | string or null | yes | hex sha256 of the predecessor rowHash ('' for the genesis row). |
rowHash | string or null | yes | hex sha256(prevHash || canonical(row)). |
createdAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
action | string | yes | The audited action, e.g. api_key.created, domain.deleted, webhook.created. |
resourceType | string or null | no | The kind of resource the action targeted, e.g. api_key, domain, inbox, webhook. |
resourceId | string or null | no | Identifier of the affected resource, when one applies. |
actor | string or null | no | Who performed the action: an API key id/prefix, a user id, or a system actor. |
ip | string or null | no | Source IP address the action originated from, when captured. |
metadata | object or null | no | Free-form, action-specific context captured with the event. Null when no metadata was recorded. |
createdAt | string (date-time) | yes | When the event was recorded (UTC). |
| Field | Type | Required | Description |
|---|
object | "phone_number.available" | yes | |
phoneNumber | string | yes | E.164. Partially masked (e.g. +16313------) when purchasable is false. |
countryCode | string | yes | |
numberType | string | yes | |
locality | string or null | no | |
region | string or null | no | |
capabilities | array of string | no | |
monthlyCostUsd | number or null | no | |
setupCostUsd | number or null | no | |
purchasable | boolean | yes | False when the provider account has not completed identity verification; the number is masked and cannot be bought yet. |
| Field | Type | Required | Description |
|---|
objectIds | array of string (uuid) | yes | The storage object ids to delete (1-1000). (min items 1, max items 1000) |
| Field | Type | Required | Description |
|---|
messageIds | array of string (uuid) | yes | The message ids to delete (1-1000). (min items 1, max items 1000) |
| Field | Type | Required | Description |
|---|
object | "batch_delete_result" | yes | |
deleted | array of string | yes | The ids that were successfully deleted. |
failed | array of object | yes | Per-id failures; never aborts the rest of the batch. |
| Field | Type | Required | Description |
|---|
to | PostalAddress | yes | |
templateData | object | no | Per-recipient values that fill the template's {{placeholders}} for this letter. |
The 202 accept envelope for a list broadcast enqueued for asynchronous fan-out.
| Field | Type | Required | Description |
|---|
object | "broadcast" | yes | |
id | string | yes | The server-minted broadcast id (bcast_...). |
audienceId | string (uuid) | yes | |
status | "queued" | yes | |
The body of an audience broadcast. Every active member of the audience receives its own email from inboxId, which must be an email inbox. Per-recipient fields (to, cc, bcc, contactId, channel, sendAt, inReplyTo, references, replyToMessageId, dryRun) and the Telegram-only buttons and telegram are rejected with 400: members are the recipients, one message each, so none of them can apply.
| Field | Type | Required | Description |
|---|
inboxId | string | yes | |
subject | string | no | (default "") |
text | string | no | |
html | string | no | |
react | ReactRenderInput | no | |
template | MessageTemplateRef | no | |
attachments | array of SendMessageAttachment | no | Outbound send attachments. 'attachment' and safe 'auto' sends are inline; current inline API limit is 10 files, 8 MiB per file, 8 MiB total decoded bytes. 'link' is explicit and must be backed by a pre-created Dairo share link placed deliberately in text/html by the caller. (max items 10) |
idempotencyKey | string | no | Per-broadcast idempotency base: each member's message is keyed {idempotencyKey}:{address}, so re-posting the same broadcast never re-sends to a member already accepted. Omitted, the base is derived from the org, the audience and the body. (max length 128) |
replyTo | string (email) | no | Optional single Reply-To address, set verbatim as the MIME Reply-To header. |
headers | map of string | no | Optional custom MIME headers ({name: value}). Spoofable/provenance headers are dropped server-side; malformed names or CR/LF are rejected. |
tags | map of string | no | Optional SES message tags ({name: value}), validated against SES tag constraints. |
ignoreComplaints | boolean | no | Override complaint and hard-bounce suppression for every member that previously complained or bounced. (default false) |
| Field | Type | Required | Description |
|---|
object | "bucket" | yes | |
id | string | yes | Bucket identifier (buk_*). |
name | string | yes | |
displayName | string or null | no | |
description | string or null | no | |
isDefault | boolean | yes | |
status | "active", "archived" | yes | |
usedBytes | integer | yes | (minimum 0) |
objectCount | integer | yes | (minimum 0) |
metadata | object or null | no | |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
object | "list" | yes | |
data | array of Bucket | yes | |
pagination | Pagination | yes | |
| Field | Type | Required | Description |
|---|
object | "bucket_object" | yes | |
id | string (uuid) | yes | |
filename | string | yes | |
contentType | string or null | no | |
bytes | integer | yes | (minimum 0) |
scanStatus | "pending", "clean", "infected", "failed", "skipped" | yes | Async malware-scan verdict (W2.2). Objects start 'pending' (owner-only, not publicly served) and become 'clean' or 'infected'/'failed' once the scanner runs. Public links (/d/, /s/) and native attach require 'clean' (or trusted 'skipped'). |
createdAt | string (date-time) | yes | |
A fail-closed spend/send budget for an account, key, or agent scope.
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
scope | "account", "key", "agent" | yes | |
scopeId | string or null | no | null for the account scope; the api_key id for key/agent scopes. |
enabled | boolean | yes | |
limits | BudgetLimits | yes | |
usage | BudgetUsage | yes | |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes | |
Budget limits. At least one limit (maxSendsPerDay, maxNewRecipientsPerHour, maxSpendPerDayCents, or hardStopOnComplaint=true) is required. maxSpendPerDayCents is allowed on the account budget only.
| Field | Type | Required | Description |
|---|
maxSendsPerDay | integer or null | no | Recipient-denominated sends allowed in a rolling 24h window. (minimum 0, maximum 1000000) |
maxNewRecipientsPerHour | integer or null | no | Recipients addressed in a rolling 1h window. V1 counts every recipient on each send (a conservative over-count); true distinct-recipient dedup is V2. (minimum 0, maximum 1000000) |
hardStopOnComplaint | boolean or null | no | When true, every send under this budget fails closed once the account has any recorded complaint. |
maxSpendPerDayCents | integer or null | no | Account budgets only: the daily money cap in USD cents. A paid hold (AI generation, phone call, letter) that would take the last 24 hours of spend past it is rejected with spend_cap_reached; 0 blocks every paid hold. (minimum 0, maximum 1000000) |
| Field | Type | Required | Description |
|---|
budgets | array of Budget | yes | |
| Field | Type | Required | Description |
|---|
budget | Budget | yes | |
| Field | Type | Required | Description |
|---|
scope | "account", "key", "agent" | yes | |
scopeId | string or null | no | Required for key/agent scopes (an api_key id you own); omit for the account scope. |
enabled | boolean | no | (default true) |
limits | BudgetLimits | yes | |
| Field | Type | Required | Description |
|---|
sendsLast24h | integer | yes | Recipient-denominated sends recorded in the last 24h for this scope. |
newRecipientsLastHour | integer | yes | Recipients addressed in the last hour for this scope. |
accountHasComplaint | boolean | yes | Whether the account has any recorded complaint (drives hardStopOnComplaint). |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
projectId | string (uuid) | no | |
userId | string (uuid) | no | |
alias | string or null | no | @-referenceable handle, unique per project. |
displayName | string | yes | |
kind | "person", "agent", "self" | yes | |
isSelf | boolean | yes | The project self contact (the "@me" recipient). |
info | string or null | no | Free-text notes. |
metadata | object | no | |
avatarUrl | string or null | no | |
handles | array of ContactHandle | no | Present on the detail view (GET /v1/contacts/{id} and /v1/contacts/me). |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
displayName | string | yes | (min length 1, max length 200) |
alias | string | no | |
kind | "person", "agent", "self" | no | |
info | string | no | (max length 10000) |
avatarUrl | string | no | |
metadata | object | no | |
handles | array of ContactHandleInput | no | |
| Field | Type | Required | Description |
|---|
contact | Contact | yes | |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
contactId | string (uuid) | yes | |
projectId | string (uuid) | no | |
userId | string (uuid) | no | |
channel | string | yes | Delivery channel of this handle (email/a2a/telegram/postal/…). |
value | string | yes | The channel address (email address, chat id, agent id, or for a postal handle the one-line formatted address). |
label | string or null | no | |
isPrimary | boolean | yes | |
verified | boolean | yes | |
metadata | object | no | Structured extras. For a postal handle this carries the structured address: { name, street, line2?, postalCode, city, state?, country } (see PostalAddress). |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
channel | string | yes | email / a2a / telegram / postal / … |
value | string | yes | The channel address. For a postal handle this is the one-line formatted address (for display); the structured address goes in metadata. (max length 500) |
label | string | no | |
isPrimary | boolean | no | (default false) |
metadata | object | no | Structured extras. REQUIRED for a postal handle: { name, street, line2?, postalCode, city, state?, country } (see PostalAddress). name/street/postalCode/city/country are required; country is an ISO-3166 alpha-2 code or a country name. |
| Field | Type | Required | Description |
|---|
object | "list" | yes | |
data | array of Contact | yes | |
pagination | Pagination | yes | |
| Field | Type | Required | Description |
|---|
displayName | string | no | (min length 1, max length 200) |
alias | string or null | no | |
kind | "person", "agent", "self" | no | |
info | string or null | no | (max length 10000) |
avatarUrl | string or null | no | |
metadata | object | no | |
| Field | Type | Required | Description |
|---|
name | string | yes | |
scopes | array of "account:read", "account:write", "admin", "agents:read", "agents:write", "audiences:read", "audiences:write", "buckets:read", "buckets:write", "budgets:read", "budgets:write", "compliance:read", "compliance:write", "contacts:read", "contacts:write", "domains:read", "domains:write", "events:read", "events:write", "inboxes:read", "inboxes:write", "keys:read", "keys:write", "letters", "letters:read", "letters:send", "messages", "messages:read", "messages:send", "phone", "phone:call", "phone:read", "phone:write", "templates:read", "templates:write", "webhooks:read", "webhooks:write" | yes | (min items 1) |
allowedIps | array of string or null | no | Optional IPv4/IPv6 addresses or CIDR ranges (up to 50) the key may authenticate from. Deny-by-default: a correct secret from an unlisted IP is rejected with 403. Omit or null for any-IP. |
environment | "test", "live", null | no | Cosmetic LABEL only; picks the secret prefix (dairo_test_…/dairo_live_…). It does NOT create a sandbox: a test key sends real mail, really delivered and really billed. Defaults to live. (default "live") |
projectId | string or null | no | Optional organization to bind the key to. Defaults to the caller's active project; you must be a member of the one you name. |
inboxIds | array of string (uuid) or null | no | Optional per-inbox restriction: the inbox ids (inboxes.id, up to 100) this key may send as. Enforced server-side on every send, so it binds a raw POST /v1/messages exactly as much as it binds the CLI. Omit, null, or [] for unrestricted (any inbox). A key that is itself restricted may only grant a subset of its own inboxes; a child that requests none inherits the parent's restriction rather than escaping it. |
| Field | Type | Required | Description |
|---|
object | "api_key" | yes | |
id | string (uuid) | yes | |
name | string | yes | |
prefix | string | yes | |
scopes | array of string | yes | |
status | "active", "revoked" | yes | |
createdAt | string (date-time) | yes | |
lastUsedAt | string (date-time) or null | no | |
allowedIps | array of string or null | no | The key's IP allowlist (IPv4/IPv6 addresses or CIDR ranges), or null when the key authenticates from any IP. |
inboxIds | array of string (uuid) or null | no | The inbox ids (inboxes.id) this key may send as. Empty or null means the key is unrestricted and may send as any inbox in the project — the default, and what every key minted before this field existed has. |
environment | "live", "test" | no | |
secret | string | yes | One-time API key secret. Store it now; it is never shown again. |
secretShownOnce | true | yes | |
| Field | Type | Required | Description |
|---|
filename | string | yes | (min length 1, max length 1024) |
contentType | string | yes | (min length 1, max length 256) |
expectedBytes | integer or null | no | Optional client-declared size; the true size is verified on finalize. (minimum 0) |
metadata | object or null | no | |
| Field | Type | Required | Description |
|---|
name | string | yes | Unique bucket name (case-insensitive per account). (min length 1, max length 128) |
displayName | string or null | no | (max length 256) |
description | string or null | no | (max length 1024) |
metadata | object or null | no | |
| Field | Type | Required | Description |
|---|
domain | string | yes | |
| Field | Type | Required | Description |
|---|
username | string | yes | |
localPart | string | no | |
domain | string | yes | |
agent | string | no | (default "Inbox Agent") |
mode | "receive_send", "send_only", "receive_only" | no | (default "receive_send") |
| Field | Type | Required | Description |
|---|
templateId | string | yes | The stored letter template rendered once per recipient. |
recipients | array of BatchRecipient | yes | (min items 1, max items 1000) |
from | PostalAddress or null | no | |
print | LetterPrintOptions | no | |
delivery | LetterDelivery | no | |
paymentSlip | "qr", "sepaDe", "sepaAt" or null | no | Optional payment-slip overlay applied to every letter. |
autoSend | boolean | no | (default true) |
notifications | boolean | no | (default true) |
metadata | object | no | |
Exactly one document source must be provided: pdfBase64, file, or templateId. Validate any letter first with POST /v1/letters/verify; GET /v1/letters/requirements has the full layout spec and compliant starter templates.
| Field | Type | Required | Description |
|---|
pdfBase64 | string or null | no | Base64-encoded PDF (alternative to file). |
file | LetterFileRef or null | no | |
fileName | string | yes | |
to | PostalAddress | yes | |
from | PostalAddress or null | no | |
print | LetterPrintOptions | no | |
delivery | LetterDelivery | no | |
autoSend | boolean | no | (default true) |
metadata | object | no | |
templateId | string or null | no | A stored letter template id. Dairo renders the template (filled with templateData) and composites the to recipient into the address window — the third document source, mutually exclusive with pdfBase64/file. Required for the structured payment object. |
templateData | object or null | no | Values for the template's {{placeholder}} variables. Ignored unless templateId is set. |
dryRun | boolean | no | When true the letter is validated, rendered, and priced exactly like a real send but is NEVER created, mailed, or charged — the response is a non-persisted status:"preview" object. The per-request no-send rehearsal. (default false) |
notifications | boolean | no | Email the account owner a status update at notable delivery milestones. (default true) |
paymentSlip | "qr", "sepaDe", "sepaAt", null | no | Bring-your-own-slip flag for a pdfBase64/file letter whose PDF already contains the slip artwork: qr (Swiss QR-bill), sepaDe, or sepaAt. Omit/null for a normal letter. To have Dairo GENERATE the slip use the structured payment object (template letters only). |
payment | LetterPayment or null | no | Structured payment object — Dairo GENERATES the payment slip (Swiss QR-bill / SEPA Zahlschein + GiroCode) and composites it full-width at the page bottom. Honored ONLY with templateId; pairing it with pdfBase64/file is a 400. |
| Field | Type | Required | Description |
|---|
name | string | yes | |
html | string | yes | The branded letter HTML. Use {{placeholders}} where values vary per recipient and leave the recipient address window blank. |
variables | array of string or LetterTemplateVariable or object | no | Declared template variables. Preferred: [{name, type?, example?, label?}]. Also accepted: an array of names, or an object {name: type}. Stored and returned in the preferred shape. |
status | LetterTemplateStatus | no | |
Options for a secure share link over a stored object.
| Field | Type | Required | Description |
|---|
password | string | no | Optional password the recipient must enter on the /s/ page: 8-256 characters, used exactly as given (never trimmed) and without a NUL character. An empty string means no password. (min length 8, max length 256) |
maxUses | integer | no | Optional use cap. 1 = one-time (the /d/ download returns 410 Gone after the first use). (minimum 1) |
expiresAt | string (date-time) | no | Optional absolute expiry (RFC3339). Must be in the future. |
| Field | Type | Required | Description |
|---|
url | string (uri) | yes | |
events | array of "message.received", "message.quarantined", "message.sent", "message.delivered", "message.bounced", "message.complained", "message.delayed", "budget.tripped", "compliance.erasure.completed", "subprocessor.changed", "object.scanned", "share_link.opened", "letter.status_changed", "call.status_changed", "domain.verified" | yes | (min items 1) |
label | string | no | Optional human label for the endpoint. Surfaced read-only and used as the primary match field by prefix-scoped test cleanup. |
| Field | Type | Required | Description |
|---|
object | "webhook" | yes | |
id | string (uuid) | yes | |
url | string (uri) | yes | |
events | array of "message.received", "message.quarantined", "message.sent", "message.delivered", "message.bounced", "message.complained", "message.delayed", "budget.tripped", "compliance.erasure.completed", "subprocessor.changed", "object.scanned", "share_link.opened", "letter.status_changed", "call.status_changed", "domain.verified" | yes | |
label | string or null | no | Optional human label for the endpoint, or null when unlabeled. |
status | "active", "paused" | yes | |
createdAt | string (date-time) | yes | |
lastDeliveryAt | string (date-time) or null | no | Timestamp of the most recent successful webhook delivery, or null before the first successful delivery. |
secondarySecretExpiresAt | string (date-time) or null | no | End of the dual-secret window after a rotation, or null. |
secondarySecretActive | boolean | no | Whether deliveries are still signed with the previous secret too. |
consecutiveFailures | integer | no | |
pausedReason | string or null | no | auto:delivery_failures when the circuit breaker paused the endpoint, else null. |
autoPaused | boolean | no | |
autoPausedAt | string (date-time) or null | no | |
signingSecret | string | yes | One-time signing secret (whsec_...). Store it now; it is never shown again. |
secretShownOnce | true | yes | |
| Field | Type | Required | Description |
|---|
deleted | boolean | yes | |
A court-usable, Ed25519-signed receipt enumerating exactly what was destroyed.
Type: SignedArtifact and object.
| Field | Type | Required | Description |
|---|
type | "CNAME", "MX", "TXT" | yes | |
host | string | yes | |
value | string | yes | |
priority | integer or null | no | |
status | "pending", "configured" | yes | |
| Field | Type | Required | Description |
|---|
object | "domain" | yes | |
id | string (uuid) | yes | |
domain | string | yes | |
status | "pending", "verified", "failed" | yes | |
verifiedAt | string (date-time) or null | no | |
region | string | yes | |
records | array of DnsRecord | yes | |
type | "custom", "included", "system" | no | |
isIncluded | boolean | no | |
isDeletable | boolean | no | |
isSystem | boolean | no | Only on the shared dairo.app system domain. |
isReadOnly | boolean | no | Only on the shared dairo.app system domain. |
receiving | "active", "pending" | no | Only on the verify response: whether the domain receives mail (it does exactly when verified). |
| Field | Type | Required | Description |
|---|
object | "list" | yes | |
data | array of Domain | yes | |
pagination | Pagination | yes | |
Edit a Telegram message you sent: exactly one of text or html, plus an optional replacement inline keyboard.
| Field | Type | Required | Description |
|---|
text | string | no | New plain-text body. Mutually exclusive with html. |
html | string | no | New rich-HTML body. Mutually exclusive with text. |
buttons | array of array of TelegramButton | no | Optional replacement inline keyboard (rows of buttons). Pass [] to clear the keyboard. Callback buttons show a feedback toast on tap (default: ✓ + the button label; set alert:true for a modal). |
| Field | Type | Required | Description |
|---|
type | "subject", "inbox" | yes | subject: erase all stored mail to or from subjectHandle. inbox: purge everything in inboxId. |
subjectHandle | string (email) | no | Required for type subject: the data subject's plain email address. |
inboxId | string (uuid) | no | Required for type inbox: the inbox to purge. |
idempotencyKey | string | no | Optional caller-supplied key; a retry with the same key returns the same job, a reuse for another target is a 409. |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
kind | "erase_subject", "purge_inbox" | yes | |
subjectHandle | string or null | no | |
inboxId | string or null | no | |
status | "pending", "running", "completed", "failed" | yes | |
deleted | ErasureJobDeletedCounts | yes | |
certificate | DeletionCertificate or null | no | |
certificateSig | string or null | no | |
error | string or null | no | |
createdAt | string (date-time) | yes | |
startedAt | string (date-time) or null | no | |
completedAt | string (date-time) or null | no | |
Acknowledgement that an erasure job was enqueued.
| Field | Type | Required | Description |
|---|
jobId | string (uuid) | yes | |
kind | "erase_subject", "purge_inbox" | yes | |
status | "pending", "running", "completed", "failed" | yes | |
createdAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
messages | integer | no | |
threads | integer | no | |
attachments | integer | no | |
s3Objects | integer | no | |
ledgerRowsRedacted | integer | no | |
| Field | Type | Required | Description |
|---|
message | string | yes | |
code | string | no | |
type | string or null | no | |
param | string or null | no | |
| Field | Type | Required | Description |
|---|
error | Error | yes | |
| Field | Type | Required | Description |
|---|
object | "list" | yes | Always "list" — the unified list envelope discriminator. |
data | array of LedgerEvent | yes | The ledger events for this page, each with seq/partitionKey join keys. (This is the array named data, not events.) |
pagination | Pagination | yes | |
gaps | array of LedgerGap | yes | Per-partition seq gaps detected within this page's window. An empty array means no gap was detected in the returned window — detection is window-local (only the seq range present on this page), not whole-history. |
| Field | Type | Required | Description |
|---|
eventId | string | yes | |
seq | integer (int64) | yes | |
partitionKey | string | yes | |
createdAt | string (date-time) | yes | |
Selects a ledger slice to re-deliver. Provide exactly one lower bound: since (an opaque cursor from GET /v1/events), sinceSeq (+inboxId, replay one partition from a seq), or sinceTimestamp (RFC3339).
| Field | Type | Required | Description |
|---|
since | string | no | Opaque keyset cursor (from GET /v1/events) to replay forward from. |
sinceSeq | integer (int64) | no | Replay one partition starting at this seq (inclusive). Requires inboxId. |
inboxId | string (uuid) | no | Scope the replay to one inbox partition (required with sinceSeq; an optional filter otherwise). |
sinceTimestamp | string (date-time) | no | Replay events created at or after this RFC3339 timestamp. |
until | string (date-time) | no | Optional upper bound (events created at or before this RFC3339 timestamp). |
types | array of string | no | Optional event-type filter, e.g. ["email.bounced"]. |
webhookId | string | no | Optional: replay only to this one webhook subscription; otherwise to every matching active subscription. |
maxEvents | integer | no | Hard cap on the slice size. A slice that exceeds the cap is rejected with 400 asking the caller to page with until/maxEvents. (minimum 1, maximum 5000, default 1000) |
| Field | Type | Required | Description |
|---|
replayed | integer | yes | Number of events re-delivered to at least one matching subscription. |
skipped | integer | yes | Number of events in the slice with no matching active subscription. |
from | EventReplayBound or null | no | |
to | EventReplayBound or null | no | |
| Field | Type | Required | Description |
|---|
object | "inbox" | yes | |
id | string (uuid) | yes | |
address | string (email) or null | yes | |
localPart | string or null | yes | |
domain | string or null | yes | |
domainStatus | "pending", "verified", "failed", null | no | |
agent | string | no | |
mode | "receive_send", "send_only", "receive_only" | yes | |
status | "active", "paused", "deleted" | yes | |
createdAt | string (date-time) or null | no | |
lastMessageAt | string (date-time) or null | no | |
channel | "email", "a2a" | yes | The channel this message transited: "email" (external, over SES) or "a2a" (internal Dairo-to-Dairo, which skips SES). Reserved future values (sms, whatsapp, …) are not yet wired. |
| Field | Type | Required | Description |
|---|
inboxes | array of Inbox | yes | |
JSON-Schema-lite extraction contract: a flat map of field name to declaration. Identical shape to a template variables schema. '{}' (or omitted) means no contract (passthrough).
Type: map of object.
| Field | Type | Required | Description |
|---|
deleted | boolean | yes | |
inboxId | string (uuid) | yes | |
| Field | Type | Required | Description |
|---|
inboxId | string (uuid) | yes | |
schema | InboxSchemaContract | yes | |
onValidationError | "quarantine", "passthrough" | yes | |
extractionHint | string or null | no | |
createdAt | string (date-time) | no | |
updatedAt | string (date-time) | no | |
One durable, ordered row of the reliability-spine event ledger. Mirrors the webhook event for the same source event (same eventId/type/data) and adds the monotonic per-partition seq plus the loop-wide idempotencyKey.
| Field | Type | Required | Description |
|---|
eventId | string | yes | The evt_<uuid> id; identical to the X-Dairo-Event-Id of the original webhook delivery, so consumer-side dedupe is exact across live delivery and replay. |
type | string | yes | Event type, e.g. email.sent, email.delivered, email.bounced, email.complained, message.received. |
seq | integer (int64) | yes | Monotonic, 1-based, contiguous sequence number within the partition. A gap in seq is a lost event (surfaced in gaps[]). |
partitionKey | string | yes | The ordering domain for seq, e.g. inbox:<uuid>. |
inboxId | string (uuid) or null | no | |
threadId | string (uuid) or null | no | |
idempotencyKey | string or null | no | Loop-wide idempotency key threaded from the originating send onto every status event and the matched inbound reply. Null when the event did not originate from an idempotent send. |
outboundMessageId | string (uuid) or null | no | |
messageId | string (uuid) or null | no | |
providerMessageId | string or null | no | |
occurredAt | string (date-time) or null | no | |
createdAt | string (date-time) | yes | |
data | object | no | The original webhook event data payload (metadata-first, body-free). |
| Field | Type | Required | Description |
|---|
partitionKey | string | yes | The partition (ordering domain) the gap was detected in, e.g. inbox:<uuid>. |
missingSeq | array of integer (int64) | yes | Sequence numbers expected-but-absent within the returned window for this partition. A non-empty list means one or more events were lost; replay to recover. |
| Field | Type | Required | Description |
|---|
object | "letter" | yes | |
id | string | yes | |
status | LetterStatus | yes | |
fileName | string or null | no | |
pageCount | integer or null | no | |
to | PostalAddress | no | |
from | PostalAddress or null | no | |
print | LetterPrintOptions | no | |
delivery | LetterDelivery | no | |
paperTypes | array of LetterPaperType | no | |
autoSend | boolean | no | |
price | LetterMoney or null | no | |
trackingNumber | string or null | no | |
metadata | object | no | |
lastEventType | string or null | no | The type of the newest event on the letter's timeline (e.g. processing, canceled); null until the letter has an event. |
lastEventAt | string (date-time) or null | no | When the newest timeline event occurred; null until the letter has an event. |
submittedAt | string (date-time) or null | no | |
canceledAt | string (date-time) or null | no | |
error | string or null | no | |
createdAt | string (date-time) or null | no | |
updatedAt | string (date-time) or null | no | |
events | array of LetterEvent | no | |
paymentSlip | "qr", "sepaDe", "sepaAt", null | no | The chosen payment-slip overlay, or null for a normal letter. |
dryRun | boolean | no | True for a validate/price-only letter that is never mailed or charged. |
providerMode | "test", "live" | no | test: the letter is validated and priced but never printed, mailed, or charged (a dry run, or the account's provider mode is test). live: it will be printed and posted. |
notifications | boolean | no | Owner milestone-email preference for this letter. |
payment | LetterPayment or null | no | The structured payment object the slip was generated from (owner records), or null. |
undeliverableReason | string or null | no | Human-readable reason when the letter reached undeliverable; null otherwise. |
batchId | string or null | no | The owning batch id for a batch-member letter; null for a single send. Pairs with the ?batchId= list filter. |
Type: "left", "right".
| Field | Type | Required | Description |
|---|
object | "letter_batch" | yes | |
id | string | yes | |
templateId | string or null | no | |
status | string | yes | |
total | integer | yes | |
completed | integer | no | Member letters in a terminal state (delivered, undeliverable, canceled, failed). |
statusCounts | map of integer | no | Live count of member letters keyed by their letter status. |
createdAt | string (date-time) or null | no | |
updatedAt | string (date-time) or null | no | |
| Field | Type | Required | Description |
|---|
object | "letter_batch" | yes | |
id | string | yes | |
total | integer | yes | Number of letters created (one per recipient). |
status | string | yes | The batch status; queued on create. |
Type: "economy", "priority", "registered".
| Field | Type | Required | Description |
|---|
object | "letter_event" | yes | |
eventId | string | yes | |
letterId | string or null | no | |
type | string | yes | |
code | string or null | no | |
description | string or null | no | |
producer | string or null | no | |
location | string or null | no | |
reason | string or null | no | Human-readable reason, when the event carries one (an undeliverable reason, or why a created letter is held, e.g. code test_mode). |
hasImage | boolean | no | |
occurredAt | string (date-time) or null | no | |
recordedAt | string (date-time) or null | no | |
Reuse a PDF already stored in Dairo as the letter — no re-upload. Provide EXACTLY ONE of attachmentId (an email attachment) or objectId (a storage object from the buckets API). Providing both, or neither, is a 400.
| Field | Type | Required | Description |
|---|
attachmentId | string | no | An email attachment id to reuse as the letter PDF. |
messageId | string or null | no | Optional message id the attachment belongs to (informational). |
objectId | string | no | A storage object id (from POST /v1/buckets/{bucketId}/objects upload + finalize) to reuse as the letter PDF. Must have passed its malware scan (clean/skipped). |
| Field | Type | Required | Description |
|---|
object | "list" | yes | |
data | array of Letter | yes | |
pagination | Pagination | yes | |
| Field | Type | Required | Description |
|---|
currency | string | yes | Upper-case ISO 4217 code, e.g. EUR. |
amount | number | yes | |
walletAmount | number | no | The price in the credits-wallet currency, at the same conversion rate the charge uses (rounded to the cent). |
walletCurrency | string | no | The credits-wallet currency (USD). |
walletRate | number | no | The conservative rate from the letter currency (EUR) to the wallet currency used for walletAmount (walletAmount = amount × walletRate, rounded to the cent). |
Type: "standard", "qr", "sepa_at", "sepa_de".
A generated payment slip: qr = Swiss QR-bill (CHF), sepaDe/sepaAt = SEPA Zahlschein + GiroCode (EUR). The debtor defaults to the letter recipient.
| Field | Type | Required | Description |
|---|
type | "qr", "sepaDe", "sepaAt" | yes | |
creditor | object | yes | The payee (account holder). |
amount | number | yes | Amount > 0, at most 2 decimals. |
currency | "CHF", "EUR", null | no | Must match type (qr => CHF, sepa* => EUR); omitted = inferred. |
reference | string or null | no | Structured payment reference. |
message | string or null | no | Unstructured remittance info (Verwendungszweck). |
debtor | LetterPaymentParty or null | no | |
| Field | Type | Required | Description |
|---|
name | string | no | |
street | string or null | no | |
houseNumber | string or null | no | |
postalCode | string or null | no | |
city | string or null | no | |
country | string or null | no | ISO 3166-1 alpha-2. |
| Field | Type | Required | Description |
|---|
object | "letter_price" | yes | |
currency | string | yes | Upper-case ISO 4217 code, e.g. EUR. |
amount | number | yes | |
walletAmount | number | no | The price in the credits-wallet currency, at the same conversion rate the charge uses (rounded to the cent). |
walletCurrency | string | no | The credits-wallet currency (USD). |
walletRate | number | no | The conservative rate from the letter currency (EUR) to the wallet currency used for walletAmount (walletAmount = amount × walletRate, rounded to the cent). |
country | string | no | |
pageCount | integer | no | |
delivery | LetterDelivery | no | |
print | LetterPrintOptions | no | |
breakdown | object | no | |
Give the destination (country or to.country) and one page source: pageCount, pdfBase64, file, or templateId (rendered with templateData and to to count pages). First match wins in that order.
| Field | Type | Required | Description |
|---|
country | string | no | ISO 3166-1 alpha-2 country code. Optional when to.country is given. |
pageCount | integer or null | no | (minimum 1) |
pdfBase64 | string or null | no | |
print | LetterPrintOptions | no | |
delivery | LetterDelivery | no | |
paperTypes | array of LetterPaperType | no | |
file | LetterFileRef | no | |
templateId | string or null | no | A stored letter template; rendered to count pages. |
templateData | object or null | no | Values for the template's placeholders. |
to | PostalAddress or null | no | Recipient. Its country prices the letter when country is absent; a template render composites it (a sample recipient is used when absent). |
Type: "color", "grayscale".
The machine-readable letter compliance spec: exact A4 address-window and keep-out coordinates (mm), PDF rules, the verify→price→dryRun→send workflow, and ready-made compliant starter templates (starterTemplates[].html can be POSTed to /v1/letters/templates verbatim).
| Field | Type | Required | Description |
|---|
object | "letter_requirements" | no | |
version | string | no | |
printMode | "test", "live" | no | The account's letter print mode, the same as letters.printMode on GET /v1/whoami. test letters are never printed. |
printModeNote | string | no | |
testMode | object | no | endState: what happens to a letter created in test mode (it stays processing, is never printed or charged, does not expire; cancel it to close it out). |
destinations | object | no | Accepted recipient countries: supportedCountries is "any" (every assigned ISO 3166-1 alpha-2 code) or the configured list; printCentreCountry is where letters are posted (domestic); registered states the domestic-only rule. |
summary | string | no | |
pageSetup | object | no | |
addressWindow | object | no | |
keepOuts | object | no | |
bodyLayout | object | no | |
pdfRules | array of string | no | |
workflow | array of object | no | |
starterTemplates | array of object | no | |
endpoints | object | no | |
agentHint | string | no | |
mcpTools | map of string | no | Which MCP tool carries each letters action (prepare_letters, list_letters, send_letters). |
Type: "simplex", "duplex".
Type: "draft", "queued", "processing", "printable", "submitted", "in_transit", "delivered", "undeliverable", "canceled", "failed".
| Field | Type | Required | Description |
|---|
object | "letter_template" | yes | |
id | string | yes | |
name | string | yes | |
html | string | no | The branded letter HTML with {{placeholders}} and a blank recipient address window. Omitted from list items. |
variables | array of LetterTemplateVariable | no | Declared template variables, always normalized to [{name, type?, example?, label?}] (legacy string[] and {name: type} rows are converted on read). |
status | LetterTemplateStatus | yes | |
createdAt | string (date-time) or null | no | |
updatedAt | string (date-time) or null | no | |
| Field | Type | Required | Description |
|---|
object | "letter_template_preview" | yes | |
templateId | string | yes | |
addressPlacement | LetterAddressPlacement | yes | |
pdfBase64 | string | no | The rendered PDF, base64. Present only for output: inline. |
pdfUrl | string (uri) or null | no | output: url only: a presigned download URL for the PDF (null when storage is unavailable). |
pdfUrlExpiresInSeconds | integer or null | no | output: url only: seconds until pdfUrl expires (900). |
pageCount | integer | no | output: url only. |
pageSize | object or null | no | output: url only: the rendered page size from the layout check. |
valid | boolean or null | no | output: url only: the layout-check verdict (null when the check was unavailable). |
summary | any | no | output: url only: the layout-check summary (null when unavailable). |
failedChecks | array of string | no | output: url only: ids of the layout checks that failed (empty when none failed or the check was unavailable). |
checks | array of object | no | output: url only: every layout check as {id, status, message}, the same list POST /v1/letters/verify returns without the expected/actual detail. |
sizeBytes | integer | no | output: url only: PDF size in bytes. |
agentHint | string | no | output: url only, when storage was unavailable. |
Type: "active", "archived".
One declared template placeholder.
| Field | Type | Required | Description |
|---|
name | string | yes | The placeholder name used as {{name}}. |
type | string | no | Optional value type hint, e.g. string, number, date. |
example | string | no | Optional sample value (used by previews). |
label | string | no | Optional human label. |
The structured layout verdict for a letter PDF.
| Field | Type | Required | Description |
|---|
object | "letter_verification" | yes | |
valid | boolean | yes | True when NO check failed. Warnings may still be present. |
pageCount | integer | no | |
pageSize | object or null | no | Page size in mm. A page within 1 mm of A4 is reported as exactly 210 x 297 with format A4. |
measuredPageSize | object or null | no | The raw measured page size, present when pageSize was reported as nominal A4 (a page within 1 mm of 210 x 297 mm, e.g. Chromium's 596 pt width). |
addressPlacement | "left", "right", null | no | The window where the recipient address was detected, or null when none was found. |
addressLines | array of string | no | The text lines detected inside the address window, top to bottom. |
checks | array of LetterVerificationCheck | yes | |
summary | string | no | |
agentHint | string | no | The recommended next step. |
One layout check verdict. fail blocks a compliant send; warn is a risk to review; skipped means the check was not applicable.
| Field | Type | Required | Description |
|---|
id | string | yes | Stable check id, e.g. page_size, address_window, address_match, franking_zone, edge_clearance, fonts_embedded. |
status | "pass", "warn", "fail", "skipped" | yes | |
message | string | yes | Agent-readable finding, with expected geometry in mm where relevant. |
expected | any | no | Machine-usable expected value, when applicable. |
actual | any | no | Machine-usable observed value, when applicable. |
Exactly one document source must be provided: pdfBase64, file, or templateId (with templateData + to — the render composites the recipient). Passing to is strongly recommended: it enables the printed-address match check.
| Field | Type | Required | Description |
|---|
pdfBase64 | string or null | no | Base64-encoded PDF to verify (max 4 MB for verification). |
file | LetterFileRef or null | no | |
templateId | string or null | no | Verify a stored template's render. Requires to. |
templateData | object or null | no | |
to | PostalAddress or null | no | The intended recipient — enables the printed-address match check. Required with templateId. |
from | PostalAddress or null | no | Optional return address (template path only). |
print | LetterPrintOptions | no | |
maxPages | integer or null | no | Optional page-count ceiling enforced as a fail check. (minimum 1) |
delivery | LetterDelivery or null | no | Pass the SAME delivery class you will send with. registered letters use a DIFFERENT address geometry — the carrier prints its registered-mail label into y=50–67mm, so the recipient block must sit in y=67–90mm — and are verified against it. Registered delivery is domestic only (the recipient must be in the print centre country, DE); with to in another country verify adds a failing registered_domestic check, and price/create reject it with 422, param delivery. |
payment | LetterPayment or null | no | The structured payment object the create will carry. Template letters are rendered WITH the generated slip so the verified PDF is the exact PDF the create would mail. Template-path only (mirrors the create's rule). |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
inboxId | string (uuid) | yes | |
threadId | string (uuid) or null | yes | |
direction | "inbound", "outbound" | yes | |
status | string | yes | |
from | MessageAddress | yes | |
to | array of string | yes | |
cc | array of string | yes | |
bcc | array of string | yes | |
subject | string | yes | |
textPreview | string | yes | |
hasHtml | boolean | yes | |
hasAttachments | boolean | yes | |
receivedAt | string (date-time) | yes | |
createdAt | string (date-time) | yes | |
textBody | string or null | no | |
htmlBody | string or null | no | |
attachments | array of MessageAttachment | no | |
structured | object or null | no | Schema-Inbox extraction result for this message: the extracted object (validated data, or the raw candidate on passthrough/quarantine). Null when no schema was configured or extraction did not run. |
extractionStatus | "skipped", "validated", "quarantined", "passthrough", "error", null | no | Outcome of the Schema-Inbox extraction stage for this message. Null when extraction did not run. |
channel | "email", "a2a" | yes | The channel this message transited: "email" (external, over SES) or "a2a" (internal Dairo-to-Dairo, which skips SES). Reserved future values (sms, whatsapp, …) are not yet wired. |
channelMetadata | object or null | no | Channel-specific metadata bag (per-channel extension point). Inbound email: {sesMessageId, spfVerdict, dkimVerdict, dmarcVerdict, …}. A2A: {receiptId, provenance, provenanceVerified}. A folded outbound send: {providerMessageId, provider, lastEventType, lastEventAt, bouncedAt, complainedAt}. |
The result of a Telegram message action (edit/react/unreact).
| Field | Type | Required | Description |
|---|
object | string | no | |
id | string | no | The message id acted on. |
channel | string | no | |
edited | boolean | no | |
editedAt | string | no | |
reacted | boolean | no | |
emoji | string | no | |
big | boolean | no | |
| Field | Type | Required | Description |
|---|
address | string | yes | |
name | string or null | no | |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
filename | string or null | no | |
contentType | string or null | no | |
sizeBytes | integer or null | no | (minimum 0) |
contentId | string or null | no | |
createdAt | string (date-time) or null | no | |
messageId | string (uuid) | no | |
disposition | "attachment", "inline", null | no | |
| Field | Type | Required | Description |
|---|
message | Message | yes | |
Send by referencing a stored template instead of an inline body. Mutually exclusive with text, html, and react: combining a template with any inline body is a 400. The referenced version is resolved and pinned at request time; supplied variables are validated against that version's variable schema (a bad variable is a synchronous 400). When the version declares a subject template it is used unless an explicit subject is provided on the request.
| Field | Type | Required | Description |
|---|
id | string | yes | Template UUID or slug, owned by the authenticated account. |
version | integer (int64) | no | Explicit version to pin. Omit to resolve and pin the template's current default version at request time. An archived template can only be sent with an explicit version. (minimum 1) |
variables | object | no | Values for the template's declared variables. Validated against the pinned version's variable schema (type, enum, maxLength, url/email format, required, defaults). Serialized size limit: 32 KiB. |
| Field | Type | Required | Description |
|---|
category | "account", "billing", "usage", "security", "product" | yes | The notification category this preference applies to. |
emailEnabled | boolean | yes | Whether the account receives email notifications in this category. Defaults to true when no preference has been set. |
| Field | Type | Required | Description |
|---|
object | "notification_preferences" | yes | |
preferences | array of NotificationPreference | yes | One entry per notification category, with its resolved emailEnabled flag. |
| Field | Type | Required | Description |
|---|
preferences | object | yes | A partial map of category -> emailEnabled. At least one known category is required; unknown category keys are rejected. |
An organization (project) the account belongs to, with the caller's role.
| Field | Type | Required | Description |
|---|
id | string or null | yes | |
name | string | no | |
slug | string | no | |
vanitySlug | string or null | no | |
role | "owner", "admin", "member", null | yes | |
| Field | Type | Required | Description |
|---|
eventId | string | yes | |
messageId | string or null | no | |
providerMessageId | string or null | no | |
type | string | yes | SES event type, e.g. Delivery, Bounce, Complaint. |
recipient | string or null | no | |
occurredAt | string or null | no | |
subject | string or null | no | |
from | string or null | no | |
to | array of string or null | no | |
status | string or null | no | |
bounceType | string or null | no | |
bounceSubType | string or null | no | |
bounceAction | string or null | no | |
bounceStatus | string or null | no | |
diagnosticCode | string or null | no | |
complaintFeedbackType | string or null | no | |
complaintUserAgent | string or null | no | |
complaintSubType | string or null | no | |
agentHint | string or null | no | |
| Field | Type | Required | Description |
|---|
id | string | yes | |
from | string or null | no | |
to | array of string or null | no | |
subject | string or null | no | |
status | string or null | no | |
sentAt | string or null | no | |
error | string or null | no | |
providerMessageId | string or null | no | |
lastEventType | string or null | no | |
lastEventAt | string or null | no | |
bouncedAt | string or null | no | |
complainedAt | string or null | no | |
createdAt | string or null | no | |
scheduledAt | string (date-time) or null | no | When the email is scheduled to send, for status scheduled. Null for immediate sends. |
canceledAt | string (date-time) or null | no | When a scheduled email was canceled, for status canceled. Null otherwise. |
| Field | Type | Required | Description |
|---|
nextCursor | string or null | yes | |
| Field | Type | Required | Description |
|---|
agent | string | no | The inbox agent's display name. |
mode | "receive_send", "send_only", "receive_only" | no | |
| Field | Type | Required | Description |
|---|
url | string (uri) | no | |
events | array of "message.received", "message.quarantined", "message.sent", "message.delivered", "message.bounced", "message.complained", "message.delayed", "budget.tripped", "compliance.erasure.completed", "subprocessor.changed", "object.scanned", "share_link.opened", "letter.status_changed", "call.status_changed", "domain.verified" | no | |
| Field | Type | Required | Description |
|---|
object | "phone_call" | yes | |
id | string (uuid) | yes | |
direction | "outbound", "inbound" | yes | outbound for calls placed with POST /v1/phone/calls, inbound for calls answered by a number's inbound agent. |
status | "queued", "initiating", "ringing", "in_progress", "completed", "failed", "no_answer", "busy", "canceled" | yes | Terminal: completed, failed, no_answer, busy, canceled. |
fromNumber | string | yes | |
toNumber | string | yes | |
instructions | string or null | no | |
greeting | string or null | no | |
voice | string or null | no | The Dairo Live voice id. |
model | string or null | no | Always dairo-live. |
language | string or null | no | |
maxDurationSeconds | integer or null | no | |
voicemailMessage | string or null | no | |
queuedAt | string (date-time) or null | no | |
startedAt | string (date-time) or null | no | |
answeredAt | string (date-time) or null | no | |
endedAt | string (date-time) or null | no | |
durationSeconds | integer or null | no | |
hangupCause | string or null | no | |
answeredBy | string or null | no | human or machine, from answering-machine detection. |
summary | string or null | no | |
notes | array of PhoneCallNote or null | no | Inbound calls: the caller's structured notes (tasks, notes, reminders, messages). |
costUsd | number or null | no | Billed per started minute: the $0.09/min Dairo Live rate plus the destination's telephony rate. Calls that never connect are free. |
error | string or null | no | |
metadata | object | no | |
idempotencyKey | string or null | no | |
createdAt | string (date-time) | yes | |
Calls are always recorded. To follow a call's progress subscribe a webhook to the call.status_changed event. The agent hangs up by itself when the person says goodbye.
| Field | Type | Required | Description |
|---|
to | string | yes | Destination, E.164. A real phone rings here. |
from | string | yes | Caller id, E.164. MUST be a number this account owns with status active. |
instructions | string | yes | What the agent should accomplish. {{name}} placeholders are filled from variables when the call is created; unknown placeholders stay as written. (max length 8000) |
greeting | string | no | Opening line spoken when the callee answers. Supports {{name}} placeholders filled from variables. |
voice | "marin", "cedar", "alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "quartz", "ripple", "vesper", "willow", "stone", "gleam", "meridian", "bossa", "tempo", "beacon", "delta", "cinder" | no | A Dairo Live voice id. marin (default), cedar, alloy, ash, ballad, coral, echo, sage, shimmer and verse are multilingual; quartz, ripple (Australian English), vesper (British English), willow, stone (Irish English), gleam, meridian (North American English), bossa, tempo (Brazilian Portuguese), beacon (Filipino English), delta, cinder (Southern U.S. English). Any other value is a 400. Browse them with GET /v1/phone/voices. (default "marin") |
model | "dairo-live" | no | The call model. Phone calls run on Dairo Live; dairo-live is the only accepted value (any other value is a 400). (default "dairo-live") |
language | string | no | ISO language code the agent speaks (e.g. en, de). |
maxDurationSeconds | integer | no | Hard cap on call length in seconds (30-780). (minimum 30, maximum 780, default 600) |
variables | object | no | Values for {{name}} placeholders in instructions and greeting, filled in at create time. Placeholders without a value stay as written. |
voicemailMessage | string | no | Message the agent leaves when the call reaches a voicemail. Without it the agent hangs up silently on a voicemail. (max length 500) |
metadata | object | no | |
idempotencyKey | string | no | A retried request returns the original call rather than dialing the human twice. |
| Field | Type | Required | Description |
|---|
object | "list" | yes | |
data | array of PhoneCall | yes | |
| Field | Type | Required | Description |
|---|
kind | "task", "note", "reminder", "message" | yes | |
text | string | yes | |
due | string or null | yes | When it is due, as the caller said it (e.g. "tomorrow"), or null. |
| Field | Type | Required | Description |
|---|
object | "phone_call.recording" | yes | |
callId | string (uuid) | yes | |
objectId | string (uuid) | yes | A Dairo storage object; fetch it through the storage API. |
| Field | Type | Required | Description |
|---|
object | "phone_call.transcript" | yes | |
callId | string (uuid) | yes | |
turns | array of PhoneCallTranscriptTurn | yes | |
| Field | Type | Required | Description |
|---|
role | "agent", "caller", "tool" | yes | |
content | string | yes | |
timestamp | string (date-time) or null | no | |
| Field | Type | Required | Description |
|---|
object | "phone_number" | yes | |
id | string (uuid) | yes | |
phoneNumber | string | yes | E.164. |
countryCode | string | yes | |
numberType | "local", "toll_free", "national", "mobile" | yes | |
capabilities | array of string | no | |
status | "pending", "active", "releasing", "released", "failed" | yes | pending means the provider reserved the number but regulatory documents are still outstanding (common for German local numbers). It is not an error. |
inboxId | string (uuid) or null | no | When set, every inbound call to this number (summary, the caller's notes and the transcript) lands in that inbox as a channel: "voice" message. |
agentId | string (uuid) or null | no | |
inboundInstructions | string or null | no | Who the inbound agent is and what the line is for. null = the default assistant that takes messages and notes. (max length 8000) |
inboundGreeting | string or null | no | Opening line for inbound calls. null = a short default greeting (by first name for a known contact). (max length 500) |
inboundVoice | "marin", "cedar", "alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "quartz", "ripple", "vesper", "willow", "stone", "gleam", "meridian", "bossa", "tempo", "beacon", "delta", "cinder", null | no | Dairo Live voice id for the inbound agent. |
inboundLanguage | string or null | no | ISO language code the inbound agent speaks. |
monthlyCostUsd | number or null | no | |
setupCostUsd | number or null | no | |
requirements | object | no | Outstanding regulatory requirements, when status is pending. |
metadata | object | no | |
purchasedAt | string (date-time) or null | no | |
releasedAt | string (date-time) or null | no | |
createdAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
phoneNumber | string | yes | E.164, exactly as returned by the availability search. |
| Field | Type | Required | Description |
|---|
object | "list" | yes | |
data | array of PhoneNumber | yes | |
| Field | Type | Required | Description |
|---|
confirm | true | yes | Releasing is irreversible: the number returns to the public pool. |
At least one property is required. An explicit null unbinds (inboxId, agentId) or resets an inbound* field to its default.
| Field | Type | Required | Description |
|---|
inboxId | string (uuid) or null | no | |
agentId | string (uuid) or null | no | |
inboundInstructions | string or null | no | Who the inbound agent is and what the line is for. null = the default assistant that takes messages and notes. (max length 8000) |
inboundGreeting | string or null | no | Opening line for inbound calls. null = a short default greeting (by first name for a known contact). (max length 500) |
inboundVoice | "marin", "cedar", "alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "quartz", "ripple", "vesper", "willow", "stone", "gleam", "meridian", "bossa", "tempo", "beacon", "delta", "cinder", null | no | Dairo Live voice id for the inbound agent. |
inboundLanguage | string or null | no | ISO language code the inbound agent speaks. |
metadata | object | no | |
| Field | Type | Required | Description |
|---|
voiceId | "marin", "cedar", "alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "quartz", "ripple", "vesper", "willow", "stone", "gleam", "meridian", "bossa", "tempo", "beacon", "delta", "cinder" | yes | Pass as voice on POST /v1/phone/calls or inboundVoice on a number. |
name | string | yes | |
description | string or null | no | |
language | "multilingual", "en", "pt" | yes | |
gender | string or null | no | |
accent | string or null | no | |
A postal address (letter to / from). Requires country plus street (with houseNumber) or poBox; a violation is a 422 whose param names the path, e.g. from.street.
| Field | Type | Required | Description |
|---|
name | string or null | no | |
company | string or null | no | |
street | string or null | no | Street name. Required unless poBox is given. |
houseNumber | string or null | no | House number; give it with street. |
poBox | string or null | no | PO box. Required unless street is given. |
addressLine2 | string or null | no | |
postalCode | string or null | no | |
city | string or null | no | |
country | string | yes | ISO 3166-1 alpha-2 country code. |
| Field | Type | Required | Description |
|---|
downloadUrl | string (uri) | yes | Presigned S3 GET URL. |
expiresInSeconds | integer | yes | (minimum 1, maximum 604800) |
| Field | Type | Required | Description |
|---|
objectId | string (uuid) | yes | |
uploadUrl | string (uri) | yes | Presigned S3 PUT URL. |
method | "PUT" | yes | |
headers | map of string | yes | Headers that MUST be sent with the PUT, exactly as given: the stored Content-Type, the declared type as x-amz-meta-content-type and the filename as x-amz-meta-filename (finalize records both). |
expiresInSeconds | integer | yes | (minimum 1, maximum 604800) |
All fields optional; the proof renders with a sample recipient and, by default, left address placement.
| Field | Type | Required | Description |
|---|
templateData | object | no | Values that fill the template's {{placeholders}} for the preview. |
addressPlacement | LetterAddressPlacement | no | |
output | "inline", "url" | no | inline (default): the PDF as pdfBase64. url: the PDF is stored and a 15-minute pdfUrl is returned with pageCount, pageSize, valid, summary, failedChecks and checks from the layout check, and no base64. (default "inline") |
| Field | Type | Required | Description |
|---|
source | string | yes | React Email TSX/JSX component source. Rendered asynchronously by Dairo in an isolated renderer with allowlisted React Email imports. (max length 65536) |
props | object | no | JSON props passed to the default exported email component. Serialized size limit: 32 KiB. |
Set the bot's emoji reaction on a Telegram message.
| Field | Type | Required | Description |
|---|
emoji | string | yes | A single Telegram-allowed reaction emoji (e.g. 👍 👎 ❤ 🔥). |
big | boolean | no | Play the big-reaction animation. (default false) |
Type: string (email) or array of string (email).
| Field | Type | Required | Description |
|---|
timeoutSec | integer | yes | How long the wait stays open, 30..=1800 seconds. expiresAt = now + timeoutSec. (minimum 30, maximum 1800) |
fromHint | string or null | no | Optional sender to accept, case-insensitive: a full address (matched exactly) or a domain (matches that domain and its subdomains, e.g. 'github.com' matches 'noreply@mail.github.com'). Never a substring match. Anything that is not an address or a domain is a 400. A hinted wait resolves only from an authenticated sender: an email whose From domain passed DMARC, or an A2A message from a Dairo inbox on a verified domain or a Dairo address. Null/absent accepts any sender except an email that failed its From domain's DMARC policy. (max length 255) |
instruction | string or null | no | Natural-language instruction for the AI matcher: which email to wait for and what to extract (e.g. 'wait for the Telnyx password-reset email and return the reset link'). An EU-resident model evaluates each inbound email against it and, on a match, resolves the wait with the extracted value in result. Absent defaults to extracting any verification/OTP/confirmation code. (max length 2000) |
idempotencyKey | string or null | no | Optional idempotency key; a retried register with the same key returns the same wait. (max length 255) |
Machine-checkable residency posture + subprocessor list.
| Field | Type | Required | Description |
|---|
type | string | yes | |
primaryRegion | string | yes | |
dataResidency | string | yes | |
noUsEgress | boolean | yes | |
controllerParent | string | no | |
cloudActExposed | boolean | no | |
enforcement | object | no | |
subprocessors | array of Subprocessor | yes | |
subprocessorListVersion | integer | yes | |
subprocessorListUpdatedAt | string (date-time) or null | no | |
checkedAt | string (date-time) | yes | |
An outbound attachment. Provide EITHER inline bytes (contentBase64) OR a storage reference (objectId) — exactly one, never both. Inline attachments require filename and are capped at 8 MiB decoded (API Gateway JSON/base64 envelope). A storage-reference attachment names a Dairo storage object you own (the objectId returned by a bucket upload's finalize, or any owned storage object); Dairo fetches its bytes server-side and native-attaches up to 24 MiB, deriving filename and contentType from the object unless you override them here. Over 24 MiB the send fails with a 413 (create a share link and place it in the body yourself; Dairo never auto-edits the body).
| Field | Type | Required | Description |
|---|
filename | string | no | Required for an inline (contentBase64) attachment. Optional for a storage-reference (objectId) attachment, where it overrides the object's stored filename; when omitted the object's filename is used. (min length 1, max length 120) |
contentType | string | no | Optional. For a storage-reference (objectId) attachment, overrides the object's stored content type; when omitted the object's content type is used. (default "application/octet-stream") |
contentBase64 | string | no | Base64-encoded inline attachment bytes. Mutually exclusive with objectId. Dairo inline attachment delivery is capped at 8 MiB decoded total to stay below API Gateway JSON/base64 envelope limits and SES v2 40 MB message limits. For larger files, upload to a Dairo bucket and reference it via objectId (native-attached up to 24 MiB). |
objectId | string | no | Storage-reference attachment: the id of a Dairo storage object you own. Mutually exclusive with contentBase64. Dairo resolves the object with an ownership check, fetches its bytes server-side, and native-attaches up to 24 MiB; over that the send fails with a 413 (no share link is auto-added). filename and contentType are derived from the object unless overridden here. |
delivery | "attachment", "link", "auto" | no | Explicit delivery mode. 'attachment' sends inline as a normal email attachment. 'auto' sends inline only when safely below inline limits; otherwise callers should use an explicit share-link flow. 'link' never mutates the email body automatically and this send endpoint does not create standalone file links; create/get a Dairo share link first and place it in text/html yourself. (default "attachment") |
| Field | Type | Required | Description |
|---|
inboxId | string | yes | |
to | Recipients | yes | |
cc | Recipients | no | |
bcc | Recipients | no | |
subject | string | no | (default "") |
text | string | no | |
html | string | no | |
idempotencyKey | string | no | Body-level idempotency key kept for current API compatibility. Prefer Idempotency-Key header for new clients. (max length 128) |
attachments | array of SendMessageAttachment | no | Outbound send attachments. 'attachment' and safe 'auto' sends are inline; current inline API limit is 10 files, 8 MiB per file, 8 MiB total decoded bytes. 'link' is explicit and must be backed by a pre-created Dairo share link placed deliberately in text/html by the caller. (max items 10) |
react | ReactRenderInput | no | |
template | MessageTemplateRef | no | |
sendAt | string (date-time) or null | no | RFC 3339 timestamp WITH an explicit timezone offset to schedule the send for a future time (max 30 days ahead). Omit to send immediately. A scheduled email starts with status scheduled and can be stopped via POST /v1/outbound-emails/{emailId}/cancel before it fires. |
channel | "email", "a2a" | no | Optional explicit delivery channel. "email" forces SES even when every recipient is a Dairo inbox; "a2a" requires every recipient to be a Dairo inbox (400 otherwise) and cannot combine with sendAt. Absent = auto (a2a when all recipients are internal, else email). Unknown values are a 400. |
replyTo | string (email) | no | Optional single Reply-To address, set verbatim as the MIME Reply-To header. |
inReplyTo | string | no | Optional RFC 5322 Message-ID this message replies to, with or without angle brackets (normalized to <id@host>). Stamped as the In-Reply-To header and used to place the sent copy in the parent's thread. Takes precedence over a custom In-Reply-To in headers. (max length 250) |
references | array of string | no | Optional References chain of RFC 5322 Message-IDs (normalized like inReplyTo, deduplicated). Defaults to [inReplyTo] when omitted and inReplyTo is set. Takes precedence over a custom References in headers. (max items 32) |
replyToMessageId | string (uuid) | no | Optional Dairo message id (from the messages API) to reply to. Resolved server-side into inReplyTo, references (the parent's References plus its Message-ID) and the parent thread. 404 when the message is not visible to the caller; 400 when it disagrees with an explicit inReplyTo. |
headers | map of string | no | Optional custom MIME headers ({name: value}). Spoofable/provenance headers are dropped server-side; malformed names or CR/LF are rejected. |
tags | map of string | no | Optional SES message tags ({name: value}), validated against SES tag constraints. |
ignoreComplaints | boolean | no | Override complaint suppression for recipients that previously complained. (default false) |
contactId | string | no | Optional contact reference: the contact's PRIMARY handle for the sending inbox's channel is added to to, so a send needs no raw address. Accepts a bare contact id, or a contact:<id> / @alias / @me ref. Recipients in to/cc/bcc may ALSO be contact references (@alias, contact:<id>, @me); raw addresses pass through unchanged. |
buttons | array of array of TelegramButton | no | Telegram inline keyboard (Telegram-channel inbox only): rows of {text, url|callback} buttons. A URL button opens a link; a callback button surfaces the tap back to you as an inbound button_tap event and shows a feedback toast on tap (default: ✓ + the button label; set alert:true for a modal). |
dryRun | boolean | no | Per-request dry run, at parity with the letters API's dryRun. When true the request is validated and the sending inbox resolved exactly as a real send would be, then a non-persisted MessagePreview (status "preview") is returned: nothing is created, queued, handed to the provider, metered, or billed. Absent or false is a normal send. Test mode is scoped to the REQUEST, not to the API key — an API key's environment label has no effect on delivery. (default false) |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
status | "sent", "scheduled", "failed", "queued" | yes | A single immediate send (POST /v1/emails without sendAt) is performed synchronously and returns 'sent' (with providerMessageId) or 'failed' — it is never accepted as 'queued' only to fail later on something knowable at submit time (oversized attachment, unverified sender, etc.). A scheduled send (sendAt in the future) returns 'scheduled'. 'queued' is returned ONLY for a bulk list broadcast (POST /v1/audiences/{id}/send), whose batches are delivered asynchronously by the worker fleet. |
providerMessageId | string or null | no | |
error | string or null | no | Public-safe failure code/message. Provider/internal text is stored internally and never returned to API clients. |
warnings | array of SendMessageWarning | yes | Warning-only delivery guidance. Complaint suppressions do not block sending; agents should surface these warnings before further contact. |
channel | "email", "a2a" | no | The channel this send transited: "email" (SES) or "a2a" (internal Dairo-to-Dairo, delivered as a receipt, providerMessageId 'a2a_…'). |
channelMetadata | object or null | no | Channel-specific delivery metadata. For a2a: {receiptId, provenance, provenanceVerified}. For email: provider send metadata. |
scheduledAt | string (date-time) or null | no | When a scheduled send will fire (RFC3339); present only when status is "scheduled". |
| Field | Type | Required | Description |
|---|
recipient | string (email) | yes | |
reason | "complaint" | yes | |
message | string | yes | |
sourceMessageId | string (uuid) or null | no | Dairo emailId that originally produced the complaint warning, when known. |
providerMessageId | string or null | no | Provider correlation ID for the complaint event, when known. |
complaintFeedbackType | string or null | no | |
complaintUserAgent | string or null | no | |
lastEventAt | string (date-time) or null | no | |
| Field | Type | Required | Description |
|---|
schema | InboxSchemaContract | no | |
onValidationError | "quarantine", "passthrough" | no | Behaviour when an extracted object fails validation. 'quarantine' (default) holds the message out of message.received and emits message.quarantined; 'passthrough' delivers it with the error attached. (default "quarantine") |
extractionHint | string or null | no | Optional free-text hint passed to the extractor as prompt context. Never executed. (max length 1000) |
A secure (stateful) share link over a stored object.
| Field | Type | Required | Description |
|---|
object | string | no | |
id | string | no | Share-link id (shr_*). |
objectId | string (uuid) | no | |
shareUrl | string | no | Branded /s/ share page URL (returned only at create time). |
downloadUrl | string | no | Branded /d/ download URL (returned only at create time). |
hasPassword | boolean | no | |
maxUses | integer or null | no | |
oneTime | boolean | no | |
usesCount | integer | no | |
expiresAt | string (date-time) or null | no | |
revoked | boolean | no | |
createdAt | string (date-time) | no | |
| Field | Type | Required | Description |
|---|
object | string | no | |
data | array of ShareLink | no | |
Open analytics for one secure share link.
| Field | Type | Required | Description |
|---|
object | string | no | |
shareLinkId | string | no | |
objectId | string (uuid) | no | |
summary | object | no | |
data | array of object | no | |
A JSON object signed with the org Ed25519 key. The signature commits to the canonical form of every field except alg/kid/signature; a verifier reconstructs those bytes and checks the signature with the public key from JWKS.
| Field | Type | Required | Description |
|---|
alg | string or null | no | EdDSA, or null when no signing key is configured. |
kid | string or null | no | Key id whose public half is published in JWKS. |
signature | string or null | no | base64url (no-pad) Ed25519 signature, or null when unsigned. |
A tenant Slack app (managed or BYO). Secret-free - the sealed OAuth client/signing secrets are never returned.
| Field | Type | Required | Description |
|---|
id | string | yes | Dairo record id. |
appId | string | yes | The Slack app id (e.g. A012ABCD0A0). |
clientId | string | yes | The OAuth client id (public; it appears in the install URL). |
name | string or null | no | Display name the app was created with (null for a BYO import). |
origin | "managed", "byo" | yes | 'managed' (Dairo minted it via the App Manifest APIs) or 'byo' (imported credentials). |
contextMode | "mentions", "ambient" | yes | 'mentions' (@mentions + DMs only) or 'ambient' (also channel message events). |
ambientMode | "off", "store" | no | 'off' (drop ambient chatter) or 'store' (persist it silently, no message.received). Present on list reads; absent on the create response. |
status | string | no | 'active' | 'deleted'. Present on list reads; absent on the create response. |
createdAt | string | no | ISO 8601 creation timestamp. Present on list reads; absent on the create response. |
A Slack app's ambient state after a patch.
| Field | Type | Required | Description |
|---|
appId | string | yes | |
contextMode | "mentions", "ambient" | yes | |
ambientMode | "off", "store" | yes | |
Create a managed or BYO Slack app. Provide origin='managed' with a configToken, or origin='byo' with the four credential fields.
| Field | Type | Required | Description |
|---|
origin | "managed", "byo" | yes | |
contextMode | "mentions", "ambient" | no | Default 'mentions'. 'ambient' also subscribes the app to channel message events. |
name | string | no | managed: display name for the app/bot (optional). |
configToken | string | no | managed only: your Slack app-configuration access token (xoxe...). Used once to mint the app, then dropped - never stored. |
appId | string | no | byo only: the existing Slack app id. |
clientId | string | no | byo only: the OAuth client id. |
clientSecret | string | no | byo only: the OAuth client secret (sealed at rest). |
signingSecret | string | no | byo only: the signing secret (sealed at rest). |
Confirmation of a soft-deleted Slack app.
| Field | Type | Required | Description |
|---|
appId | string | yes | |
status | string | yes | 'deleted'. |
The account's tenant Slack apps.
| Field | Type | Required | Description |
|---|
apps | array of SlackApp | yes | |
The only mutable field on a Slack app.
| Field | Type | Required | Description |
|---|
ambientMode | "off", "store" | yes | 'store' requires a context_mode='ambient' app. |
A pasteable Slack app manifest for the self-setup flow.
| Field | Type | Required | Description |
|---|
manifest | object | yes | The Slack app manifest JSON to paste into Slack's 'Create app from manifest' flow. |
The signed Slack OAuth install URL to present as an "Add to Slack" button.
| Field | Type | Required | Description |
|---|
name | string | yes | |
role | string | yes | |
region | string | yes | |
country | string or null | no | |
url | string or null | no | |
status | "active", "removed" | yes | |
A Telegram inline-keyboard button: a text label plus exactly one of url (a http/https/tg link) or callback (an opaque action string surfaced back to you as an inbound button_tap event). A callback button shows a feedback toast on tap (default: ✓ + the button label); set alert:true for a modal. feedback/alert are ignored on a url button.
| Field | Type | Required | Description |
|---|
text | string | no | Button label (1-64 chars). |
url | string | no | A http://, https://, or tg:// link opened on tap. Mutually exclusive with callback. |
callback | string | no | An opaque action string. On tap it is surfaced back to you as an inbound button_tap message + a message.button.tapped event. Mutually exclusive with url. |
feedback | string | no | Callback-button only: the toast text shown to the tapping user (answerCallbackQuery text, max 200 chars). Defaults to '✓ <button label>' when omitted, so every tap gives visible feedback. Ignored on a url button. |
alert | boolean | no | Callback-button only: when true, the feedback is shown as a modal dialog (show_alert) instead of a transient toast. Ignored on a url button. |
| Field | Type | Required | Description |
|---|
slug | string | yes | Stable handle; use as telegram.voice.voiceId. |
name | string | yes | |
description | string or null | no | |
bestLanguage | string or null | no | |
languages | array of string | no | |
gender | string or null | no | |
tags | array of string | no | |
featured | boolean | yes | |
popularity | integer | no | |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
slug | string | yes | |
name | string | yes | |
description | string or null | no | |
currentVersion | integer or null | no | |
status | string | yes | |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
slug | string | yes | |
name | string | yes | (min length 1) |
description | string | no | |
source | string | yes | React Email TSX source for version 1. |
subject | string | no | |
variables | TemplateVariableSchema | no | |
notes | string | no | |
| Field | Type | Required | Description |
|---|
deleted | boolean | yes | |
id | string (uuid) | yes | |
| Field | Type | Required | Description |
|---|
templates | array of Template | yes | |
| Field | Type | Required | Description |
|---|
name | string | no | (min length 1) |
description | string or null | no | |
currentVersion | integer | no | (minimum 1) |
| Field | Type | Required | Description |
|---|
template | Template | yes | |
JSON-Schema-lite variable contract: a flat map of variable name to declaration.
Type: map of object.
| Field | Type | Required | Description |
|---|
version | integer | yes | |
subject | string or null | no | |
variables | object | yes | |
notes | string or null | no | |
createdAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
version | integer | yes | |
source | string | yes | |
subject | string or null | no | |
variables | object | yes | |
notes | string or null | no | |
createdAt | string (date-time) | yes | |
| Field | Type | Required | Description |
|---|
templateId | string (uuid) | yes | |
versions | array of TemplateVersion | yes | |
| Field | Type | Required | Description |
|---|
source | string | yes | React Email TSX source for the new version. |
subject | string | no | |
variables | TemplateVariableSchema | no | |
promote | boolean | no | Advance currentVersion to this version. Defaults to true. |
notes | string | no | |
| Field | Type | Required | Description |
|---|
id | string (uuid) | yes | |
inboxId | string (uuid) | yes | |
subject | string | yes | |
messageCount | integer | yes | (minimum 0) |
lastMessageAt | string (date-time) or null | yes | |
updatedAt | string (date-time) | yes | |
status | string | yes | |
lastMessagePreview | string or null | yes | |
createdAt | string (date-time) | yes | |
channel | "email", "a2a" | yes | The channel this message transited: "email" (external, over SES) or "a2a" (internal Dairo-to-Dairo, which skips SES). Reserved future values (sms, whatsapp, …) are not yet wired. |
| Field | Type | Required | Description |
|---|
object | "thread" | no | |
id | string (uuid) | yes | |
inboxId | string (uuid) | yes | |
subject | string | yes | |
messageCount | integer | yes | (minimum 0) |
lastMessageAt | string (date-time) or null | yes | |
updatedAt | string (date-time) | yes | |
status | string | yes | |
lastMessagePreview | string or null | yes | |
createdAt | string (date-time) | yes | |
channel | "email", "a2a" | yes | The channel this message transited: "email" (external, over SES) or "a2a" (internal Dairo-to-Dairo, which skips SES). Reserved future values (sms, whatsapp, …) are not yet wired. |
messages | array of Message | yes | |
At least one of name, allowedIps or inboxIds is required. scopes is deliberately absent: scopes are immutable after mint, and revoking is DELETE on this same path. Sending either is a 400 rather than a silently-ignored no-op.
| Field | Type | Required | Description |
|---|
name | string | no | New display name. Omit to leave it unchanged; null is rejected with 400 rather than silently ignored. |
allowedIps | array of string | no | Replaces the whole allowlist; it never merges. Omit the field to leave the current allowlist unchanged, or pass an empty array to clear it so the key may authenticate from any IP. Entries are IPv4/IPv6 addresses or CIDR ranges (up to 50); deny-by-default, so a correct secret from an unlisted IP is rejected with 403. Explicit null is rejected with 400 — unlike on create it does not mean any IP here, and it used to be a silently-ignored no-op. |
inboxIds | array of string (uuid) | no | Replaces the whole per-inbox restriction; it never merges. Omit to leave it unchanged, or pass an empty array to clear it so the key may send as any inbox. A restricted key may only ever narrow to a subset of its own inboxes — it cannot unpin itself or a sibling. Explicit null is rejected with 400: unlike on create it does not mean unrestricted here, it would change nothing. |
| Field | Type | Required | Description |
|---|
displayName | string or null | no | (max length 256) |
description | string or null | no | (max length 1024) |
metadata | object or null | no | |
Partial update. Provide at least one of name, html, variables, or status.
| Field | Type | Required | Description |
|---|
name | string | no | |
html | string | no | |
variables | array of string or LetterTemplateVariable or object | no | Declared template variables. Preferred: [{name, type?, example?, label?}]. Also accepted: an array of names, or an object {name: type}. Stored and returned in the preferred shape. |
status | LetterTemplateStatus | no | |
A durable await_verification wait. status is pending until it resolves (a code was extracted from an inbound message) or expires (deadline passed / canceled). Resolution outputs (result, from, messageId, resolvedAt) are present only once resolved.
| Field | Type | Required | Description |
|---|
waitId | string (uuid) | yes | |
inboxId | string (uuid) | yes | |
agentId | string (uuid) or null | no | The Agent Passport that registered this wait, when the API key was agent-bound. |
status | "pending", "resolved", "expired" | yes | |
fromHint | string or null | no | |
instruction | string or null | no | The natural-language matcher instruction this wait was registered with. |
result | string or null | no | The value the AI matcher extracted per the instruction (present once resolved) — a code, a link, or a quoted line. |
from | string or null | no | The From address of the message that resolved the wait. |
messageId | string (uuid) or null | no | The inbound message that resolved the wait. |
idempotencyKey | string or null | no | |
expiresAt | string (date-time) | yes | |
createdAt | string (date-time) | yes | |
resolvedAt | string (date-time) or null | no | |
expiredAt | string (date-time) or null | no | |
| Field | Type | Required | Description |
|---|
object | "webhook" | yes | |
id | string (uuid) | yes | |
url | string (uri) | yes | |
events | array of "message.received", "message.quarantined", "message.sent", "message.delivered", "message.bounced", "message.complained", "message.delayed", "budget.tripped", "compliance.erasure.completed", "subprocessor.changed", "object.scanned", "share_link.opened", "letter.status_changed", "call.status_changed", "domain.verified" | yes | |
label | string or null | no | Optional human label for the endpoint, or null when unlabeled. |
status | "active", "paused" | yes | |
createdAt | string (date-time) | yes | |
lastDeliveryAt | string (date-time) or null | no | Timestamp of the most recent successful webhook delivery, or null before the first successful delivery. |
secondarySecretExpiresAt | string (date-time) or null | no | End of the dual-secret window after a rotation, or null. |
secondarySecretActive | boolean | no | Whether deliveries are still signed with the previous secret too. |
consecutiveFailures | integer | no | |
pausedReason | string or null | no | auto:delivery_failures when the circuit breaker paused the endpoint, else null. |
autoPaused | boolean | no | |
autoPausedAt | string (date-time) or null | no | |
| Field | Type | Required | Description |
|---|
webhooks | array of Webhook | yes | |
| Field | Type | Required | Description |
|---|
id | string | yes | |
scopes | array of string | yes | |
| Field | Type | Required | Description |
|---|
userId | string | yes | |
projectId | string or null | no | |
apiKey | WhoamiApiKey | yes | |
plan | string | yes | |
limits | object | yes | |
usage | object | yes | |
period | object | yes | |
notes | object | yes | |
storage | WhoamiStorage | yes | |
organization | ActiveOrganization | no | |
organizations | array of Organization | no | Every organization the account is a member of (the org switcher list). |
letters | object | no | Physical-mail status for this account, so you know before sending whether a letter will really be printed. |
| Field | Type | Required | Description |
|---|
usedBytes | integer (int64) | yes | |
limitBytes | integer (int64) | yes | |
remainingBytes | integer (int64) | yes | |
breakdown | WhoamiStorageBreakdown | yes | |
| Field | Type | Required | Description |
|---|
mailBodyBytes | integer (int64) | yes | |
attachmentBytes | integer (int64) | yes | |
fileBytes | integer (int64) | yes | |
expiringFileBytes | integer (int64) | yes | |
activeFileObjects | integer (int64) | yes | |