Gent API Documentation

Domains

Verify a custom domain to send and receive email from your own addresses (e.g. agent@yourco.com). All endpoints require a user auth session token.

Setup flow
  1. Add the domain — POST /v1/domains/ returns the DNS records to configure.
  2. Add all five records at your DNS registrar (MX, SPF, DKIM, DMARC, gent-verify).
  3. Trigger verification — POST /v1/domains/{name}/verify/ runs a DNS check. Repeat until status is verified.
  4. Create inboxes with "address": "agent@yourco.com".

The gent-verify TXT record can be removed after the domain is verified. The other four records must remain in place for mail to work.

For a customer-owned sending subdomain used only with Gent, p=reject is the recommended DMARC policy because all legitimate mail for that subdomain should flow through Gent. For an existing or root domain, start with p=quarantine while reports confirm every legitimate sender passes alignment, then move to p=reject.

GET /v1/domains/reference/ List domain setup contract  user auth
{ "resource": "domains", "payload": {...}, "dns_record_types": [...], "dmarc_policy_guidance": [...], "setup": { "records_source": "POST /v1/domains/ and GET /v1/domains/{name}/ return domain-specific dns_records.", "subdomain_strategy": "Use a customer-owned sending subdomain when isolating reputation is important.", "dmarc_default": "domain_use=dedicated_subdomain means a customer-owned subdomain and defaults to reject. Existing/root domains default to quarantine unless dmarc_policy is explicitly set." } }
DMARC guidance: use p=reject for a customer-owned subdomain when all legitimate mail for that subdomain should be sent by Gent. Use p=quarantine for existing or root domains until reports show legitimate senders are aligned.
GET /v1/domains/dns-record-types/ List DNS record types  user auth
{ "resource": "domain_dns_record_types", "dns_record_types": [{ "type": "MX" }, { "type": "TXT", "name": "DMARC" }], "counts": {"dns_record_types": 5} }
POST /v1/domains/ Add a domain → domain_id  user auth
Request
{ "domain": "mail.yourco.com" }
domain_use is optional. Omitted requests use existing_domain and default DMARC to quarantine. For a subdomain reserved only for Gent/agent mail, pass "domain_use": "dedicated_subdomain"; that defaults DMARC to reject unless dmarc_policy is explicitly set.
Reserved subdomain request
{ "domain": "agents.yourco.com", "domain_use": "dedicated_subdomain" }
201 Created — includes required DNS records
{ "domain_id": "<domain-id>", "domain": "mail.yourco.com", "status": "pending", "dmarc_policy": "quarantine", "verified_at": null, "dns_records": { "mx": { "type": "MX", "name": "mail.yourco.com.", "value": "10 mail.gent.mx." }, "spf": { "type": "TXT", "name": "mail.yourco.com.", "value": "v=spf1 a:mail.gent.mx ~all" }, "dkim": { "type": "TXT", "name": "gent1._domainkey.mail.yourco.com.", "value": "v=DKIM1; k=rsa; p=<public-key>" }, "dmarc": { "type": "TXT", "name": "_dmarc.mail.yourco.com.", "value": "v=DMARC1; p=quarantine; rua=mailto:dmarc@gent.mx" }, "verification": { "type": "TXT", "name": "_gent-verify.mail.yourco.com.", "value": "gent-site-verification=<token>" } } }
GET /v1/domains/ List all domains for the tenant  user auth
[{ "domain_id": "<domain-id>", "domain": "yourco.com", "status": "verified", "verified_at": "2026-05-01T10:00:00Z", "dns_records": { } }]
POST /v1/domains/{name}/verify/ Trigger DNS verification — returns updated domain  user auth
Runs all five DNS checks synchronously. Repeat after each DNS change until status is verified. DNS propagation can take up to 48 hours.
GET /v1/domains/{name}/check/ Per-record verification status — does not mutate domain  user auth
Response
{ "domain": "yourco.com", "checks": { "mx": true, "spf": true, "dkim": false, "dmarc": true, "verification": true } }
DELETE /v1/domains/{name}/ Remove domain — 409 if active inboxes exist  user auth
# 204 No Content — empty body
Inboxes

An inbox is a programmable email address on a verified custom domain, and the unit of access control, configuration, and storage. How you organize inboxes depends on your use case: one per agent, one per workflow, one per client, or one shared across a team. All endpoints in this section require a user auth session token.

GET /v1/tenants/reference/ List tenant configuration options  tenant admin
200 OK
{ "version": "2026-06-06", "resource": "tenants", "payload": { "update_tenant": { "method": "PATCH", "path": "/v1/tenants/" }, "update_caps": { "method": "PUT", "paths": [...] } }, "fields": [...], "workflow_review_policy": { "defaults": { "on_missing_required": "hold_for_review" }, "review_modes": ["auto", "hold_for_review", "delayed_auto_approve", "skip", "fail"] }, "cap_builder": { "modes": [...], "resources": [...] }, "file_owner_deletion_policies": ["transfer_to_tenant_admin", "purge"], "cap_modes": ["enforce", "allow_and_bill"], "user_roles": ["owner", "admin", "member"] }
Tenant admins receive tenant-managed options for building workspace settings screens, including workflow review defaults. Use workflow_review_defaults on PATCH /v1/tenants/ to decide whether uncertain, missing, shape-changed, or risky workflow output should hold for review, skip, fail, or use delayed auto-approval.
GET /v1/tenants/cap-resources/ List configurable cap resources  tenant admin
{ "resource": "tenant_cap_resources", "resources": [{ "resource": "mailbox", "scope": "inbox" }, { "resource": "files", "scope": "tenant" }], "counts": {"resources": 3} }
GET /v1/tenants/cap-modes/ List cap behavior modes  tenant admin
{ "resource": "tenant_cap_modes", "modes": [{ "value": "enforce" }, { "value": "allow_and_bill" }], "counts": {"modes": 2} }
POST /v1/inboxes/ Create an inbox → inbox_id  user auth
Request — domain must be verified first
{ "address": "agent@yourco.com" }
201 Created
{ "inbox_id": "...", "tenant_id": "...", "address": "agent@yourco.com", "email_domain": "yourco.com", "status": "active", "created_at": "2026-05-14T10:00:00Z", "updated_at": "2026-05-14T10:00:00Z" }
GET /v1/inboxes/ List all inboxes for your tenant  user auth
[ { "inbox_id": "...", "tenant_id": "...", "address": "agent@example.com", "email_domain": "example.com", "status": "active", "created_at": "2026-01-10T09:00:00Z", "updated_at": "2026-05-22T14:30:00Z" } ]
GET /v1/inboxes/{inbox_id}/ Retrieve an inbox  user auth
{ "inbox_id": "...", "tenant_id": "...", "address": "agent@example.com", "email_domain": "example.com", "status": "active", "created_at": "2026-01-10T09:00:00Z", "updated_at": "2026-05-22T14:30:00Z" }
DEL /v1/inboxes/{inbox_id}/ Initiate inbox closure  user auth
# 204 No Content — empty body
GET /v1/inboxes/{inbox_id}/imports/reference/ Mail import builder contract  tenant admin
200 OK
{ "resource": "mailbox_imports", "providers": [{ "provider": "imap", "mail_only": true, "continuous_sync": false, "supports_rerun": true, "supports_resume": false }], "security_modes": [...], "auth_modes": [...], "options": { "folders": { "allowed": ["all", "named", "include_regex"] } } }
Imports are mail-only migrations into the destination inbox. They do not import contacts, calendars, filtering rules, or continuous sync state. Rerun starts a fresh import attempt; Lambda workers do not provide durable archive resume.
POST /v1/inboxes/{inbox_id}/imports/ Create a mail import job → import_id  tenant admin
Request — password is write-only
{ "provider": "imap", "source": { "host": "imap.gmail.com", "port": 993, "security": "tls", "username": "old@gmail.com", "auth": { "mode": "password", "password": "app-password" } }, "options": { "folders": "all", "dry_run": false } }
201 Created
{ "import_id": "imp_...", "inbox_id": "...", "source": { "host": "imap.gmail.com", "username": "old@gmail.com", "auth": { "mode": "password", "has_secret": true } }, "status": "pending", "progress": { "phase": "created" } }
For Gmail, use a 16-character Gmail app password, not the Google account password. OAuth provider authorization flows are not exposed in v1.
GET /v1/inboxes/{inbox_id}/imports/ List import jobs for an inbox  tenant admin
[{ "import_id": "imp_...", "status": "pending" }]
GET /v1/inboxes/{inbox_id}/imports/{import_id}/ Retrieve an import job  tenant admin
{ "import_id": "imp_...", "status": "running", "progress": { "phase": "copying", "messages_imported": 1200 } }
POST /v1/inboxes/{inbox_id}/imports/{import_id}/start/ Queue an import job  tenant admin
# 200 OK — returns updated import job
POST /v1/inboxes/{inbox_id}/imports/{import_id}/rerun/ Queue a fresh import attempt  tenant admin
# 200 OK — rerun does not resume the previous transfer
POST /v1/inboxes/{inbox_id}/imports/{import_id}/cancel/ Cancel a pending or running import  tenant admin
# 200 OK — returns updated import job
GET /v1/inboxes/{inbox_id}/handoff/ Handoff context — paused tokens, open threads, recent activity  user auth
{ "inbox_id": "...", "generated_at": "2026-05-17T10:30:00Z", "paused_tokens": [{ "token_id": "...", "label": "My Agent", "paused_at": "..." }], "open_threads": [...], "recent_activity": [...], "active_relationships": [...] }
FieldTypeRequiredDescription
recent_activityarrayoptionalLast 30 timeline entries.
active_relationshipsarrayoptionalTop 10 contacts by recency (30-day window)
GET /v1/inboxes/{inbox_id}/quota/ Storage quota for an inbox  session auth
200 OK
{ "used_bytes": 52428800, "limit_bytes": 1073741824, "used_pct": 4.88 }
FieldTypeRequiredDescription
used_pctnumberoptional0.0–100.0; 0.0 when no limit is configured.
Returns live storage usage from the mail server. 502 if the mail server is unreachable.
→ Inbox field reference
Inbox status: active — normal operation. suspended — outbound blocked, inbound continues. closing — deletion initiated, data retained for 30 days. purged — terminal, address released. Deleting an inbox via DELETE moves it to closing; it is not immediately removed.
Tokens

Tokens are API keys scoped to a single inbox. Create one token per agent or integration. The raw token value is shown exactly once — at creation or rotation. Store it immediately. All endpoints in this section require a user auth session token.

GET /v1/tokens/reference/ List available token scopes  no auth required; admins see admin-only scopes
200 OK
{ "version": "2026-06-06", "resource": "tokens", "payload": { "create_token": { "method": "POST", "path": "/v1/tokens/" }, "token_action": { "method": "PATCH", "path": "/v1/tokens/{token_id}/" } }, "fields": [...], "scope_builder": { "preset_source": "composites", "scope_source": "scopes", "default_preset": "write" }, "scopes": [ { "scope": "email:read", "group": "Email", "description": "Read messages and threads", "destructive": false, "admin": false } ], "composites": { "read": ["email:read", "contacts:read"], "write": ["email:read", "email:send"], "full": ["email:read", "email:send", "email:delete"] } }
Unauthenticated and member callers receive non-admin scopes. Tenant owners/admins also receive tenant-admin scopes such as approval management scopes marked with "admin": true.
POST /v1/tokens/ Create a token → token_id  user auth
Request
{ "inbox_id": "you@example.com", "scopes": ["email:send"], "label": "string", "expires_at": "datetime", "requires_approval": ["email:send", "email:delete"] }
FieldTypeRequiredDescription
inbox_idstringrequired
scopesarrayrequiredOne or more scope strings (see table)
labelstringrequiredHuman-readable name.
expires_atstringoptionalISO 8601, omit for no expiry.
requires_approvalarrayoptionalScopes that queue actions for human review. Set at token creation; create a replacement token to change it.
201 Created
{ "token_id": "...", "inbox_id": "...", "scopes": ["email:send"], "label": "My Agent", "token_prefix": "aB3xKz9m", "status": "active", "expires_at": null, "requires_approval": ["email:send", "email:delete"], "raw_token": "gent_aB3xKz9m..." }
GET /v1/tokens/?inbox_id={id} List tokens for an inbox  user auth
[ { "token_id": "...", "inbox_id": "...", "scopes": ["email:send", "email:read"], "label": "My Agent", "token_prefix": "aB3xKz9m", "status": "active", "expires_at": null, "requires_approval": [], "created_at": "2026-05-01T10:00:00Z" } ]
PATCH /v1/tokens/{token_id}/?inbox_id= Rotate, pause, or resume a token  user auth
Request — action must be one of rotate · pause · resume
{ "action": "rotate" }
FieldTypeRequiredDescription
actionstringoptionalOne of: rotate, pause, resume.
200 OK — rotate returns new token with raw_token; pause/resume return updated token
{ "token_id": "...", "inbox_id": "...", "scopes": ["email:send", "email:read"], "label": "My Agent", "token_prefix": "aB3xKz9m", "status": "active", "expires_at": null, "requires_approval": [], "raw_token": "gent_newToken..." }
GET /v1/tokens/{token_id}/?inbox_id= Retrieve token metadata  user auth
{ "token_id": "...", "inbox_id": "...", "scopes": ["email:send", "email:read"], "label": "My Agent", "token_prefix": "aB3xKz9m", "status": "active", "expires_at": null, "requires_approval": [], "created_at": "2026-05-01T10:00:00Z" }
DEL /v1/tokens/{token_id}/?inbox_id= Revoke a token  user auth
# 204 No Content — empty body
→ Token field reference
Token format: gent_<base64url-43-chars> — 32 random bytes, 256 bits of entropy. Only the SHA-256 digest is stored; the raw value cannot be recovered. Revoking a token takes effect immediately on the next API call.
Plan gate — pause/resume: The pause and resume actions on PATCH /v1/tokens/{token_id}/ require the governance feature tier to be token_controls or higher. Tenants below this tier receive 403 Forbidden.
inbox_id behaviour by endpoint: For Messages, Calendar, Contacts, Labels, Tasks, and Agenda endpoints (search is via ?q= on the list endpoint), inbox_id is auto-derived from an agent token and does not need to be supplied. Users authenticating with a session token still pass it as documented since they may own multiple inboxes. For most other inbox-scoped endpoints (Event Notifications, Send/Mailbox Caps, Sender Rules, Forwarding, Intelligence, Audit), inbox_id must be supplied — either as a query parameter or in the request body as documented per endpoint. Tenant/workspace endpoints such as Files caps use the caller's tenant instead.
Inbox Settings

Configure per-inbox settings and outbound webhooks. Webhooks deliver event payloads to your server in real time — configure a URL and sign with a secret for verified delivery. All endpoints in this section require a user auth session token.

GET /v1/inboxes/{inbox_id}/config/ Retrieve all inbox settings  user auth
{ "default_timezone": "America/New_York", "missed_reply_threshold_days": 3, "signature": "Best,\nAlice", "label_inference_threshold": 0.65, "webhook": { "url": "https://your-server.com/webhook", "events": ["message.received"], "has_secret": true } }
FieldTypeRequiredDescription
default_timezonestringoptionalIANA — used to display event/message times.
missed_reply_threshold_daysnumberoptionalNull = feature disabled.
signaturestringoptionalNull = no signature; plain text or HTML.
label_inference_thresholdnumberoptionalNull = use default (0.65)
PATCH /v1/inboxes/{inbox_id}/config/ Update inbox settings  user auth
Request — all fields optional; only supplied keys are changed
{ "default_timezone": "America/New_York", "missed_reply_threshold_days": 3, "signature": "Best,\nAlice", "label_inference_threshold": 0.7, "webhook": { "url": "https://your-server.com/webhook", "events": ["message.received", "message.sent", "message.delivered", "message.bounced"], "secret": "your-signing-secret" } }
FieldTypeRequiredDescription
default_timezonestringoptionalIANA timezone — e.g. "Europe/London", "UTC".
missed_reply_threshold_daysnumberoptionalNull to disable.
signaturestringoptionalPlain text or HTML; "" or null to clear.
label_inference_thresholdnumberoptional0.0–1.0; null to reset to default.
webhookobjectoptionalWebhook config block: {"url", "events", "secret"}. url must be HTTPS. events is optional and defaults to ["message.received"].
webhook.secretstringoptionalOptional; omit to keep current secret, empty string to clear.
200 OK — returns full updated config
GET /v1/inboxes/{inbox_id}/webhook/ Retrieve webhook config  user auth
{ "url": "https://your-server.com/webhook", "events": ["message.received"], "has_secret": true }
Returns 404 if no webhook is configured.
PUT /v1/inboxes/{inbox_id}/webhook/ Create or replace webhook config  user auth
Request
{ "url": "https://your-server.com/webhook", "events": ["message.received"], "secret": "your-signing-secret" }
FieldTypeRequiredDescription
urlstringoptionalMust be HTTPS.
eventsarrayoptionalDefaults to ["message.received"].
secretstringoptionalOptional HMAC-SHA256 signing secret.
200 OK
{ "url": "https://your-server.com/webhook", "events": ["message.received"], "has_secret": true }
DEL /v1/inboxes/{inbox_id}/webhook/ Remove webhook config  user auth
# 204 No Content — empty body
→ Inbox config field reference
default_timezone: All times are stored in UTC. When default_timezone is set to an IANA timezone (e.g. America/New_York) it affects all datetime handling across the API:
  • Messagesreceived_at / sent_at are returned as LocalDateTime strings in this timezone
  • Calendar eventsstart is returned in this timezone; time_zone on each event reflects it; events created without an explicit time_zone use it as the default
  • Filter inputs — naive after/before params on messages and calendar are treated as being in this timezone before converting to UTC
  • Time Utils — omitting timezone in the parse endpoint automatically uses this timezone
If unset, UTC is used throughout. Use Time Utils to convert arbitrary datetime strings.
Webhook signing: When a secret is set, Gent adds an X-Gent-Signature header to each delivery — an HMAC-SHA256 hex digest of the raw request body keyed with your secret. Verify it server-side to reject forged payloads. The secret is write-only; only has_secret: true/false is ever returned.
missed_reply_threshold_days: When set, threads with no reply from the inbox owner after this many days appear in the handoff snapshot (GET /v1/inboxes/{inbox_id}/handoff/) and can trigger event notifications. Set to null to disable.
label_inference_threshold: Confidence threshold (0.0–1.0) for the label_suggest feature. A label is suggested only when its confidence score meets or exceeds this value. Default is 0.65 when not set. Lower values surface more (noisier) suggestions; higher values surface fewer (more precise) ones.
signature: Plain text or HTML, max 2 000 characters. Automatically appended to outbound messages sent via POST /v1/messages/ and to send_reply workflow writes. A plain-text version is always derived from the signature (HTML tags stripped) and appended to the text_body after a -- separator; if the message also has an html_body, the HTML signature is appended there too. Signatures are not applied to forwarded messages or system emails. Set to "" or null to clear.
collaboration_opt_in: Boolean (default false). When true, this inbox participates in team collaboration features — overlap detection, expertise discovery, and new-member onboarding. Only active when the parent tenant also has collaboration_enabled: true (team governance plan, admin-controlled). Members opt in individually; the admin enables the feature tenant-wide.
Sender Rules

Control who your agent can communicate with. Configure separate modes for inbound (who can reach the inbox) and outbound (who the agent can send to). Default mode is open — no restrictions.

GET /v1/sender-rules/reference/ List sender rule builder contract  scope: workflows:read
{ "resource": "sender_rules", "fields": [...], "modes": [{ "value": "open" }, { "value": "allowlist" }, { "value": "blocklist" }], "pattern_help": {...} }
GET /v1/sender-rules/modes/ List sender rule modes  scope: workflows:read
{ "resource": "sender_rule_modes", "modes": [...], "counts": {"modes": 3} }
PUT /v1/sender-rules/ Set sender rules  scope: workflows:write
Request
{ "inbox_id": "string", "inbound_mode": "allowlist", "outbound_mode": "open", "inbound_patterns": ["@trusted.com", "user@x.com"], "outbound_patterns": [] }
FieldTypeRequiredDescription
inbox_idstringrequired
inbound_modestringoptionalOne of: open, allowlist, blocklist.
outbound_modestringoptionalOne of: open, allowlist, blocklist.
inbound_patternsarrayoptionalDomain or address patterns.
outbound_patternsarrayoptionalEmpty = no outbound restrictions.
200 OK
{ "inbox_id": "...", "inbound_mode": "allowlist", "outbound_mode": "open", "inbound_patterns": ["@trusted.com", "user@x.com"], "outbound_patterns": [], "created_at": "2026-05-01T10:00:00Z", "updated_at": "2026-05-17T09:00:00Z" }
GET /v1/sender-rules/?inbox_id={id} Get sender rule config for an inbox  scope: workflows:read
{ "inbox_id": "...", "inbound_mode": "allowlist", "outbound_mode": "open", "inbound_patterns": ["@trusted.com", "user@x.com"], "outbound_patterns": [], "created_at": "2026-05-01T10:00:00Z", "updated_at": "2026-05-17T09:00:00Z" }
DEL /v1/sender-rules/ Remove sender rules (resets to open)  scope: workflows:write
# 204 No Content — empty body
→ Sender rules field reference
Patterns are matched against the sender or recipient address. Use @domain.com to match all addresses on a domain, or user@domain.com for an exact match. Inbound blocks drop the message silently at the SMTP layer — the sender receives no delivery failure. Outbound blocks return a 403 to the agent's API call.
Forwarding

Forward copies of incoming messages to external addresses. Configure a default forward address or create conditional rules that forward selectively based on sender, subject, or recipient. Forwarding is additive — the original message stays in the inbox.

GET /v1/forwarding/reference/ List forwarding builder contract  scope: workflows:read
{ "resource": "forwarding", "config_fields": [...], "rule_fields": [...], "condition_types": [...] }
GET /v1/forwarding/condition-types/ List forwarding rule conditions  scope: workflows:read
{ "resource": "forwarding_condition_types", "condition_types": [{ "value": "all" }, { "value": "sender" }], "counts": {"condition_types": 4} }
PUT /v1/forwarding/ Configure forwarding  scope: workflows:write
Request
{ "inbox_id": "string", "default_address": "human@yourco.com", "enabled": true }
FieldTypeRequiredDescription
inbox_idstringrequired
default_addressstringoptionalForward all incoming to this address.
200 OK
{ "inbox_id": "...", "default_address": "human@yourco.com", "enabled": true, "created_at": "2026-05-01T10:00:00Z", "updated_at": "2026-05-17T09:00:00Z" }
GET /v1/forwarding/?inbox_id={id} Get forwarding config  scope: workflows:read
{ "inbox_id": "...", "default_address": "human@yourco.com", "enabled": true, "created_at": "2026-05-01T10:00:00Z", "updated_at": "2026-05-17T09:00:00Z" }
DEL /v1/forwarding/ Disable forwarding  scope: workflows:write
# 204 No Content — empty body
POST /v1/forwarding/rules/ Create a forwarding rule  scope: workflows:write
Request
{ "inbox_id": "string", "destination": "escalation@yourco.com", "condition_type": "domain", "condition_value": "vip-client.com", "priority": 1, "enabled": true }
FieldTypeRequiredDescription
inbox_idstringrequired
destinationstringrequiredForward target.
condition_typestringrequiredOne of: all, sender, domain, subject_keyword.
condition_valuestringconditionalRequired for sender, domain, and subject_keyword; ignored for all.
prioritynumberoptionalLower = higher priority.
201 Created
{ "rule_id": "...", "inbox_id": "...", "destination": "escalation@yourco.com", "condition_type": "domain", "condition_value": "vip-client.com", "priority": 1, "enabled": true, "created_at": "2026-05-17T10:00:00Z", "updated_at": "2026-05-17T10:00:00Z" }
GET /v1/forwarding/rules/?inbox_id={id} List forwarding rules
[ { "rule_id": "...", "inbox_id": "...", "destination": "escalation@yourco.com", "condition_type": "domain", "condition_value": "vip-client.com", "priority": 1, "enabled": true, "created_at": "2026-05-17T10:00:00Z", "updated_at": "2026-05-17T10:00:00Z" } ]
PATCH /v1/forwarding/rules/{rule_id}/ Update a rule
Request — all fields optional
{ "destination": "escalation@yourco.com", "condition_type": "domain", "condition_value": "vip-client.com", "priority": 1, "enabled": true }
FieldTypeRequiredDescription
destinationstringoptional
condition_typestringoptional
condition_valuestringoptional
prioritynumberoptional
enabledbooleanoptional
200 OK
{ "rule_id": "...", "inbox_id": "...", "destination": "escalation@yourco.com", "condition_type": "domain", "condition_value": "vip-client.com", "priority": 1, "enabled": true, "created_at": "2026-05-17T10:00:00Z", "updated_at": "2026-05-17T10:00:00Z" }
DEL /v1/forwarding/rules/{rule_id}/ Delete a rule
# 204 No Content — empty body
→ Forwarding config field reference
Rules are evaluated in priority order (ascending). A message matching multiple rules forwards to each matching destination. Setting condition_type: "all" creates a catch-all rule that forwards every incoming message. Rules without a default_address config only forward when a rule matches.
Unsubscribe headers: Forwarded messages generated by a rule include RFC 2369 List-Unsubscribe and RFC 8058 List-Unsubscribe-Post headers, plus an Unsubscribe: footer line appended to the text body. Each link encodes a per-rule, per-destination HMAC token. When the destination clicks Unsubscribe, that address is suppressed from future forwards by this rule. The original sender is unaffected.
Invites

Manage team invitations for your tenant. Invites are session-authenticated and require owner or admin role — they cannot be created with agent tokens. Accepted invites provision a new user account in the tenant.

GET /v1/invites/ List invites  session auth
200 OK
[{ "token": "<invite-token>", "role": "member", "email": "alice@example.com", "expires_at": "2026-06-15T00:00:00Z", "status": "pending" }]
FieldTypeRequiredDescription
rolestringoptionalOne of: member, admin, owner.
emailstringoptionalNull = open invite (any email).
statusstringoptionalOne of: pending, accepted, cancelled, expired.
POST /v1/invites/ Create an invite  session auth
Request — all fields optional
{ "role": "member", "email": "alice@example.com", "expires_at": "2026-06-15T00:00:00Z" }
FieldTypeRequiredDescription
rolestringoptionalOne of: member, admin, owner. Default: member.
emailstringoptionalRestrict to one email; null = open invite.
expires_atstringoptionalISO 8601 datetime; null = no expiry.
201 Created
{ "token": "<invite-token>", "role": "member", "email": "alice@example.com", "expires_at": "2026-06-15T00:00:00Z", "status": "pending" }
GET /v1/invites/{token}/ Get an invite — no auth required
200 OK
{ "token": "<invite-token>", "role": "member", "email": "alice@example.com", "status": "pending" }
Used by the signup flow to pre-fill email and role. Returns 400 if the token is expired or already accepted.
DEL /v1/invites/{token}/ Cancel an invite  session auth
204 No Content
Cancels the invite. Already-accepted invites cannot be cancelled.