{"openapi":"3.0.0","paths":{"/v1/workspaces/{workspace_id}/brand":{"get":{"operationId":"BrandController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get the resolved brand tokens for the workspace. Always returns a complete object, with platform defaults filling in any unset fields.","tags":["brand"],"x-pc-sdk":{"resource":"brand","method":"retrieve","bind":["workspace_id"],"paginated":false}},"put":{"operationId":"BrandController_update","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBrandDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure on the brand payload.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Replace the workspace brand. Any field omitted from the body is reset to the platform default for that field. To partially-update, send back what GET returned with the desired diff applied.","tags":["brand"],"x-pc-sdk":{"resource":"brand","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"operationId":"BrandController_reset","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Brand customisations cleared.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Remove all brand customizations and revert to platform defaults.","tags":["brand"],"x-pc-sdk":{"resource":"brand","method":"reset","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/deliverability":{"get":{"operationId":"DeliverabilityController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"window_days","required":false,"in":"query","description":"Lookback in days, 1–90. Defaults to 14 — the length of the outage in tasks/mail-api/002.","schema":{"default":14,"type":"number"},"example":14}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliverabilityDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"window_days out of range.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Not authenticated.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"403":{"description":"Missing mail.message.read, or the mail service is not enabled.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Deliverability verdict for the workspace over a lookback window. `unconfirmed` means mail was handed off and nothing came back either way — it is not a synonym for healthy.","tags":["deliverability"],"x-pc-sdk":{"resource":"deliverability","method":"retrieve","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/messages":{"get":{"description":"One row per recipient delivery, newest first. Filters combine with AND: `q` (free text over recipient, from, subject, message id and Message-ID), `status` (any of, repeatable), `domain_id`, `api_key_id`, `source`, `template`, `created_after` / `created_before` (at most 30 days apart), plus the legacy `recipient` and `subject_contains`. `GET /messages/export` takes exactly the same filters and returns the same rows.","operationId":"OutboundMessageController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"q","required":false,"in":"query","description":"Free-text search, case-insensitive. Matches a substring of the recipient, the from address or the subject, or exactly a message id (uuid) or a Message-ID (the provider message id, with or without its `<…@…>` domain).","schema":{"maxLength":200,"example":"invoice","type":"string"},"example":"invoice"},{"name":"status","required":false,"in":"query","description":"Only messages in any of these statuses. Repeat the parameter (`status=bounced&status=complained`), use the bracket form (`status[]=bounced&status[]=complained`) or comma-separate the values (`status=bounced,complained`); a single value is the original single-status filter.","schema":{"example":["bounced","complained"],"type":"array","items":{"type":"string","enum":["queued","sent","delivered","bounced","complained","failed","suppressed","deferred"]}},"example":["bounced","complained"]},{"name":"domain_id","required":false,"in":"query","description":"Only messages sent from this domain (`domain.id`).","schema":{"format":"uuid","example":"3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b","type":"string"},"example":"3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b"},{"name":"api_key_id","required":false,"in":"query","description":"Only messages sent with this Platform API Key. Recorded from 2026-10-12; older messages have no key.","schema":{"format":"uuid","example":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d","type":"string"},"example":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"},{"name":"source","required":false,"in":"query","description":"How the message was sent: `api_key` (a Platform API Key), `dashboard` (a signed-in person, in the console or through MCP), `platform` (in-cluster product mail), `test_send` (a template test send). Recorded from 2026-10-12; older messages all read `platform`.","schema":{"example":"api_key","enum":["api_key","dashboard","platform","test_send"],"type":"string"},"example":"api_key"},{"name":"template","required":false,"in":"query","description":"Filter by template name.","schema":{"example":"welcome","type":"string"},"example":"welcome"},{"name":"created_after","required":false,"in":"query","description":"Only messages created at or after this instant. With `created_before`, the window may span at most 30 days (the log retention).","schema":{"format":"date-time","example":"2026-10-05T00:00:00Z","type":"string"},"example":"2026-10-05T00:00:00Z"},{"name":"created_before","required":false,"in":"query","description":"Only messages created before this instant. Without `created_after`, the window is the 30 days before it.","schema":{"format":"date-time","example":"2026-10-12T00:00:00Z","type":"string"},"example":"2026-10-12T00:00:00Z"},{"name":"recipient","required":false,"in":"query","description":"Legacy: filter by exact recipient address. Prefer `q`.","schema":{"example":"jane@example.com","type":"string"},"example":"jane@example.com"},{"name":"subject_contains","required":false,"in":"query","description":"Legacy: substring filter on subject (case-insensitive, max 200 chars). Prefer `q`.","schema":{"maxLength":200,"example":"Your receipt","type":"string"},"example":"Your receipt"},{"name":"limit","required":false,"in":"query","description":"Page size, 1–100","schema":{"default":20,"example":20,"type":"integer"},"example":20},{"name":"cursor","required":false,"in":"query","description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","schema":{"type":"string"},"example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOutboundMessagesResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid filter or cursor: an unknown status or source, a malformed uuid or date-time, `q` over 200 characters, `created_after` not earlier than `created_before`, or a window wider than 30 days. The reason is in `message`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List outbound messages with cursor pagination","tags":["outbound-messages"],"x-pc-sdk":{"resource":"messages","method":"list","bind":["workspace_id"],"paginated":true}},"delete":{"description":"The bulk GDPR erase (`messages.erase` in the SDKs): removes every delivery-log row sent to one recipient address in this workspace (with its stored body and events), and strips the address from the cc, bcc and reply-to lists of other rows, in one transaction. Repeating it is harmless (the second call deletes 0 rows).","operationId":"OutboundMessageController_deleteByRecipient","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"recipient","required":true,"in":"query","description":"The recipient address whose messages to erase (matched case-insensitively).","schema":{"type":"string","format":"email"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteByRecipientResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Missing or invalid recipient.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"RTBF: delete every message log row for `recipient` (case-insensitive). Returns the deleted-row count.","tags":["outbound-messages"],"x-pc-sdk":{"resource":"messages","method":"erase","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/messages/export":{"get":{"description":"Columns: id, created_at, sent_at, delivered_at, deferred_at, deferral_count, from_address, to_address, subject, template_name, status, spf_result, dkim_result, dmarc_result, bounce_code, bounce_detail, api_key_id, source, domain. The filters are resolved by the same code as `GET /messages`, so the same query string exports exactly the rows the list pages through. A rejected filter (400) does not count against the hourly cap.","operationId":"OutboundMessageController_exportCsv","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"q","required":false,"in":"query","description":"Free-text search, case-insensitive. Matches a substring of the recipient, the from address or the subject, or exactly a message id (uuid) or a Message-ID (the provider message id, with or without its `<…@…>` domain).","schema":{"maxLength":200,"example":"invoice","type":"string"},"example":"invoice"},{"name":"status","required":false,"in":"query","description":"Only messages in any of these statuses. Repeat the parameter (`status=bounced&status=complained`), use the bracket form (`status[]=bounced&status[]=complained`) or comma-separate the values (`status=bounced,complained`); a single value is the original single-status filter.","schema":{"example":["bounced","complained"],"type":"array","items":{"type":"string","enum":["queued","sent","delivered","bounced","complained","failed","suppressed","deferred"]}},"example":["bounced","complained"]},{"name":"domain_id","required":false,"in":"query","description":"Only messages sent from this domain (`domain.id`).","schema":{"format":"uuid","example":"3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b","type":"string"},"example":"3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b"},{"name":"api_key_id","required":false,"in":"query","description":"Only messages sent with this Platform API Key. Recorded from 2026-10-12; older messages have no key.","schema":{"format":"uuid","example":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d","type":"string"},"example":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"},{"name":"source","required":false,"in":"query","description":"How the message was sent: `api_key` (a Platform API Key), `dashboard` (a signed-in person, in the console or through MCP), `platform` (in-cluster product mail), `test_send` (a template test send). Recorded from 2026-10-12; older messages all read `platform`.","schema":{"example":"api_key","enum":["api_key","dashboard","platform","test_send"],"type":"string"},"example":"api_key"},{"name":"template","required":false,"in":"query","description":"Filter by template name.","schema":{"example":"welcome","type":"string"},"example":"welcome"},{"name":"created_after","required":false,"in":"query","description":"Only messages created at or after this instant. With `created_before`, the window may span at most 30 days (the log retention).","schema":{"format":"date-time","example":"2026-10-05T00:00:00Z","type":"string"},"example":"2026-10-05T00:00:00Z"},{"name":"created_before","required":false,"in":"query","description":"Only messages created before this instant. Without `created_after`, the window is the 30 days before it.","schema":{"format":"date-time","example":"2026-10-12T00:00:00Z","type":"string"},"example":"2026-10-12T00:00:00Z"},{"name":"recipient","required":false,"in":"query","description":"Legacy: filter by exact recipient address. Prefer `q`.","schema":{"example":"jane@example.com","type":"string"},"example":"jane@example.com"},{"name":"subject_contains","required":false,"in":"query","description":"Legacy: substring filter on subject (case-insensitive, max 200 chars). Prefer `q`.","schema":{"maxLength":200,"example":"Your receipt","type":"string"},"example":"Your receipt"}],"responses":{"200":{"description":"text/csv stream with one header row + one row per message. Content-Disposition: attachment.","content":{"text/csv":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid filter: an unknown status or source, a malformed uuid or date-time, `q` over 200 characters, `created_after` not earlier than `created_before`, or a window wider than 30 days. The reason is in `message`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"Another export is already running, or this workspace has hit the hourly export cap. Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Stream the filtered message log as CSV. Same filters as GET /messages. Body columns are intentionally omitted; bodies remain gated by `mail.message.body.read`. Rate-limited 1 concurrent + 5/hour per workspace.","tags":["outbound-messages"],"x-pc-sdk":{"resource":"messages","method":"export","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/messages/settings":{"get":{"operationId":"OutboundMessageController_getSettings","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundMessageSettingsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Read this workspace's outbound-message settings. Absent → defaults (redact_bodies: false).","tags":["outbound-messages"],"x-pc-sdk":{"resource":"messages.settings","method":"retrieve","bind":["workspace_id"],"paginated":false}},"patch":{"operationId":"OutboundMessageController_updateSettings","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOutboundMessageSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundMessageSettingsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid payload.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Update this workspace's outbound-message settings. Gated on `mail.message.delete` — same privilege bar as RTBF, since both touch the PII boundary.","tags":["outbound-messages"],"x-pc-sdk":{"resource":"messages.settings","method":"update","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/messages/{id}":{"get":{"operationId":"OutboundMessageController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the message.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundMessageDetailDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Not found.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a single outbound message (metadata + delivery verdicts; body not included) with its event timeline: `events[]` oldest first, `last_event`, `transport`, `bounce_type`, `bounce_subtype`. Use /:id/body for cleartext content.","tags":["outbound-messages"],"x-pc-sdk":{"resource":"messages","method":"retrieve","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/messages/{id}/body":{"get":{"operationId":"OutboundMessageController_getBody","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the message.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundMessageWithBodyDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Not found.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get the cleartext body of an outbound message. Gated by `mail.message.body.read` (admin+ by default; not granted to plain members).","tags":["outbound-messages"],"x-pc-sdk":{"resource":"messages","method":"body","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains":{"post":{"description":"Accepts Resend's create-domain body as well as ours: `name` for `fqdn`, `capabilities` for `intent`, `custom_return_path` for the MAIL FROM label, and `region`, `tls`, `open_tracking`, `click_tracking`, `tracking_subdomain`. Defaults to sending only (`intent: send`), as Resend does. Options we do not offer yet are refused with 422 rather than ignored.","operationId":"DomainController_createDomain","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure on the request body: no `fqdn`/`name`, `fqdn` and `name` disagree, `intent` and `capabilities` disagree or enable nothing (`INVALID_CAPABILITIES`), or `custom_return_path` on a receive-only domain (`MAIL_FROM_NOT_SENDING`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","INVALID_CAPABILITIES","MAIL_FROM_NOT_SENDING"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"Domain already registered (globally unique); `MAIL_FROM_HOST_IN_USE`: the `custom_return_path` host already has records that are not ours (listed in `details.found`); or `IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different body or route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","MAIL_FROM_HOST_IN_USE","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"`REGION_NOT_AVAILABLE`: `region` is not the region this deployment sends from (`details.available`); `TLS_ENFORCED_NOT_AVAILABLE`: `tls: enforced`; `TRACKING_NOT_AVAILABLE`: open/click tracking or a tracking subdomain.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","REGION_NOT_AVAILABLE","TLS_ENFORCED_NOT_AVAILABLE","TRACKING_NOT_AVAILABLE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Register a domain for a workspace","tags":["domains"],"x-pc-sdk":{"resource":"domains","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"DomainController_listDomains","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"},{"name":"search","required":false,"in":"query","schema":{"type":"string","maxLength":200},"description":"Case-insensitive substring match on the domain fqdn."},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["not_started","pending","partially_verified","verified","temporary_failure","failed","disabled","active"]},"description":"Filter by `verification_status` (`not_started`, `pending`, `partially_verified`, `verified`, `temporary_failure`, `failed`, `disabled`), applied in the query so the cursor keeps its meaning. The legacy `status` value `active` is still accepted and matches `status = active`. `pending` now means the `verification_status` (checked, not verified yet, within 72 h); before 2026-10 it matched `status = pending`, which is `not_started`, `pending`, `partially_verified` and the pending part of `failed`. Unrecognised values are rejected with a 400.","example":"not_started"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid cursor, search term, or status filter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List domains registered to this workspace (newest first), cursor-paginated.","tags":["domains"],"x-pc-sdk":{"resource":"domains","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/domains/lookup":{"get":{"description":"Creates nothing. Resolves only names at or under `fqdn` and its zone apex, plus the Domain Connect endpoints the zone advertises (fetched through the SSRF guard; cached per zone for an hour). Limited to 30 lookups per workspace per minute.","operationId":"DomainController_lookupDomain","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"fqdn","required":true,"in":"query","description":"Domain to look up (not created).","schema":{"format":"hostname","example":"acme.com","type":"string"},"example":"acme.com"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainLookupDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`fqdn` missing or not a domain name.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 30 lookups this minute (`RATE_LIMITED`). Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the next lookup is allowed.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Look up a domain before adding it: zone, DNS provider, Domain Connect support, a better subdomain, existing records.","tags":["domains"],"x-pc-sdk":{"resource":"domains","method":"lookup","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}":{"get":{"description":"The domain with `verification_status`, `region`, the effective `dns_provider`, `recommended_pending`, its DNS instructions, and `events`: the latest 20 domain events, newest first.","operationId":"DomainController_getDomain","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainDetailDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`domain_id` is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a single domain (with DNS instructions and its latest events).","tags":["domains"],"x-pc-sdk":{"resource":"domains","method":"retrieve","bind":["workspace_id"],"paginated":false,"poll":{"field":"status","terminal":["active","disabled"]}}},"patch":{"description":"`intent` (or Resend's `capabilities`) changes what the domain is used for. A pending domain just changes; a verified domain gaining sending or receiving has the new records checked live and is refused with 409 `CAPABILITY_NOT_VERIFIED` (the records to publish in `details.records`) until they pass. Turning receiving off is refused while active mailboxes exist (409 `DOMAIN_HAS_MAILBOXES`, the mailboxes in `details.mailboxes`; deleted mailboxes do not count); turning sending off also turns the custom MAIL FROM off. `tls`, `open_tracking`, `click_tracking` and `tracking_subdomain` are accepted for Resend compatibility; only the values in effect today pass (422 otherwise). `dns_provider` is the provider the setup wizard renders host names for. `mail_from_subdomain` sets the custom MAIL FROM label (`bounce` → `bounce.<fqdn>`; `null` turns it off): the domain's record set gains the MAIL FROM MX + SPF records, and once the domain is verified its MAIL FROM is pointed there (the default return address stays in use until the MX record is found, so mail never stops). Refused with 409 when that host already carries records that are not ours. `dmarc_managed: false` hides the `_dmarc` recommendation for domains whose DMARC is managed elsewhere (the policy is still detected and graded).","operationId":"DomainController_updateDomain","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDomainDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure on the request body; `intent` and `capabilities` disagree or enable nothing (`INVALID_CAPABILITIES`); or `mail_from_subdomain` on a receive-only domain (`MAIL_FROM_NOT_SENDING`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","INVALID_CAPABILITIES","MAIL_FROM_NOT_SENDING"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`CAPABILITY_NOT_VERIFIED`: a verified domain cannot gain sending or receiving until the new records verify (`details.failing`, `details.records`); `DOMAIN_HAS_MAILBOXES`: receiving cannot be turned off while active mailboxes exist (`details.count`, `details.mailboxes[].id|address`); `MAIL_FROM_HOST_IN_USE`: the MAIL FROM host already has a CNAME, a foreign MX or a foreign SPF record (listed in `details.found`); or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","CAPABILITY_NOT_VERIFIED","DOMAIN_HAS_MAILBOXES","MAIL_FROM_HOST_IN_USE","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"`TLS_ENFORCED_NOT_AVAILABLE`: `tls: enforced`; `TRACKING_NOT_AVAILABLE`: open/click tracking or a tracking subdomain.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","TLS_ENFORCED_NOT_AVAILABLE","TRACKING_NOT_AVAILABLE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"`mail_from_subdomain` or `intent` changed less than 10 seconds ago (`RATE_LIMITED`). Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the next change is allowed.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Update domain settings: capabilities, DNS provider hint, custom MAIL FROM subdomain, DMARC recommendation.","tags":["domains"],"x-pc-sdk":{"resource":"domains","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"description":"Permanently deletes the domain, its DNS record set and its Amazon SES sending identity. Mailboxes you already deleted on it are erased with it, together with the mail they still held and its stored files; this cannot be undone. Refused with 409 `DOMAIN_HAS_MAILBOXES` while any mailbox on it is active.","operationId":"DomainController_deleteDomain","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Domain deleted, with its deleted mailboxes and their remaining mail.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`DOMAIN_HAS_MAILBOXES`: the domain still has active mailboxes. `details.count` is how many; `details.mailboxes` lists them (`id`, `address`, first 100). Delete them, then try again.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","DOMAIN_HAS_MAILBOXES"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"503":{"description":"`SES_IDENTITY_DELETE_FAILED`: the domain's Amazon SES identity could not be removed. Nothing was deleted; retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["SERVICE_UNAVAILABLE","SES_IDENTITY_DELETE_FAILED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete a domain (must have no active mailboxes left).","tags":["domains"],"x-pc-sdk":{"resource":"domains","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/events":{"get":{"description":"Added, records found, verified, degraded, failing, recovered, MAIL FROM verified, DMARC detected, check failed. An event is written only when something changed, so a domain checked every few minutes does not grow a row per check.","operationId":"DomainController_listDomainEvents","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainEventsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid cursor, or `domain_id` is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List a domain's events (its timeline), newest first, cursor-paginated.","tags":["domains"],"x-pc-sdk":{"resource":"domains.events","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/verify":{"post":{"description":"Legacy shape, kept as an alias of `POST .../dns-records/check`: returns the domain on success and a 400 with `dns_check_results` when a required record fails. New integrations should use `POST .../dns-records/check`, which returns per-record states.","operationId":"DomainController_verifyDomain","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Verification failed — one or more required records are still missing or wrong.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Verified less than 10 seconds ago (`RATE_LIMITED`). Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the next attempt is allowed.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Run a synchronous DNS check against this domain; flips status to active when the required record set passes.","tags":["domains"],"x-pc-sdk":{"resource":"domains","method":"verify","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/dns-records":{"get":{"description":"Every record the domain needs for its intent, with its state (`missing`, `mismatch`, `conflict`, `propagating`, `verified`), what was found, a propagation hint and timestamps, as of the last check (the verifier re-checks pending domains every 5 minutes and active ones hourly). Does not run a DNS lookup; use `POST .../dns-records/check` for that.","operationId":"DomainController_getDnsRecords","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"zone","required":false,"in":"query","schema":{"type":"string","format":"hostname","example":"example.com"},"description":"Render `name_relative` against this zone (the domain itself or one of its parents). Defaults to the zone found by walking SOA records.","example":"example.com"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainDnsRecordsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`zone` is not the domain or one of its parents (`INVALID_ZONE`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","INVALID_ZONE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Per-record DNS status for a domain.","tags":["domains"],"x-pc-sdk":{"resource":"domains.dnsRecords","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/dns-records/export":{"get":{"description":"`format=bind`: a zone-file fragment (`$ORIGIN <zone>.`, `$TTL 3600`, names relative to the zone, MX with priority, TXT split into ≤255-byte quoted strings, a comment per record with its purpose, required/recommended and any conflict) that Cloudflare and Route 53 import directly. `format=csv`: `type,name,value,priority,ttl,purpose,required` (the common DNS-import columns plus two), RFC 4180 quoting, fully qualified names. By default only records not yet verified; `all=true` for every record. Served as an attachment.","operationId":"DomainController_exportDnsRecords","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"format","required":true,"in":"query","description":"File format: `bind` (a zone-file fragment, `text/dns`) or `csv`.","schema":{"type":"string","enum":["bind","csv"]},"example":"bind"},{"name":"zone","required":false,"in":"query","schema":{"type":"string","format":"hostname","example":"example.com"},"description":"BIND: the `$ORIGIN` names are relative to (the domain or one of its parents). Defaults to the detected zone, else the domain itself.","example":"example.com"},{"name":"all","required":false,"in":"query","schema":{"type":"boolean","default":false},"description":"Include records that already verify.","example":false}],"responses":{"200":{"description":"The file.","content":{"text/dns":{"schema":{"type":"string","example":"$ORIGIN example.com.\n$TTL 3600\n; dkim (required)\nproductcraft._domainkey.mail\t3600\tIN\tTXT\t\"v=DKIM1; k=rsa; p=MIIB...\" \"...IDAQAB\"\n"}},"text/csv":{"schema":{"type":"string","example":"type,name,value,priority,ttl,purpose,required\r\nTXT,productcraft._domainkey.mail.example.com,v=DKIM1; k=rsa; p=MIIB...,,3600,dkim,true\r\n"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`format` missing or not `bind`/`csv`, or `zone` is not the domain or one of its parents.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Download the domain's DNS records as a BIND zone fragment or a CSV.","tags":["domains"],"x-pc-sdk":{"resource":"domains.dnsRecords","method":"export","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/dns-records/check":{"post":{"description":"Queries the zone's authoritative nameservers and a public resolver for every record, stores the result, flips a pending domain whose required records pass to `active`, and returns the same body as `GET .../dns-records`. Never fails because records are missing: their states say so. Limited to one call per domain every 10 seconds. Safe to retry: it changes nothing but the stored check result, so it takes no Idempotency-Key.","operationId":"DomainController_checkDnsRecords","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"zone","required":false,"in":"query","schema":{"type":"string","format":"hostname","example":"example.com"},"description":"As on `GET .../dns-records`.","example":"example.com"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainDnsRecordsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`zone` is not the domain or one of its parents (`INVALID_ZONE`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","INVALID_ZONE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Checked less than 10 seconds ago (`RATE_LIMITED`). Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the next check is allowed.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Check the domain's DNS records now.","tags":["domains"],"x-pc-sdk":{"resource":"domains.dnsRecords","method":"check","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/share-links":{"post":{"description":"Returns a link (valid 1–7 days, default 7) to a public page that shows the domain name, its DNS records with copy-ready values, their live status and zone-file / CSV downloads, without an account. The page shows nothing else about the workspace. The link is shown only in this response (only its hash is stored); revoke it with `DELETE .../share-links/{link_id}`. Optionally emails it from ProductCraft to up to 5 recipients per domain per day (20 per workspace). Requires `mail.update` on the domain.","operationId":"ShareLinkController_create","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A replay returns the same link and sends no second email.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateShareLinkDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedShareLinkDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure: `expires_in_days` outside 1–7, more than 5 `email_to` entries, or an invalid address.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the key was used with a different body. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"The daily email cap for the domain (5 recipients) or the workspace (20) would be exceeded (`RATE_LIMITED`). No link is created. Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the cap resets (midnight UTC).","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"503":{"description":"`EMAIL_UNAVAILABLE`: `email_to` was given but the email cap cannot be checked right now. No link is created; retry, or create it without `email_to`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["SERVICE_UNAVAILABLE","EMAIL_UNAVAILABLE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create a share link: a read-only DNS setup page for whoever manages the domain's DNS.","tags":["domains"],"x-pc-sdk":{"resource":"domains.shareLinks","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"description":"The links themselves are not returned: they are shown once, at creation.","operationId":"ShareLinkController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListShareLinksResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid cursor, or an id is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List the domain's share links (newest first, including expired and revoked), cursor-paginated.","tags":["domains"],"x-pc-sdk":{"resource":"domains.shareLinks","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/share-links/{link_id}":{"delete":{"description":"The public page and its downloads answer 404 from now on. Revoking an already revoked or expired link succeeds and changes nothing.","operationId":"ShareLinkController_revoke","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"link_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the link.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Revoked.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"An id is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain or share link not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Revoke a share link.","tags":["domains"],"x-pc-sdk":{"resource":"domains.shareLinks","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/public/domain-setup/{token}":{"get":{"description":"What a share link opens: the domain name, every DNS record it needs with its live state, the DKIM signing check, and download links. Nothing about the workspace. States are as of the last check (every 5 minutes while the domain is pending). Answers 404 for an unknown, expired or revoked link. Limited to 60 requests per minute per IP.","operationId":"PublicDomainSetupController_get","parameters":[{"name":"token","required":true,"in":"path","description":"The share token from the link (43 characters, base64url).","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"}},{"name":"zone","required":false,"in":"query","schema":{"type":"string","format":"hostname","example":"example.com"},"description":"Render `name_relative` against this zone (the domain or one of its parents).","example":"example.com"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicDomainSetupDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`zone` is not the domain or one of its parents (`INVALID_ZONE`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","INVALID_ZONE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Unknown, expired or revoked link (`SHARE_LINK_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","SHARE_LINK_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 60 requests this minute from this IP (`RATE_LIMITED`). Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the next request is allowed.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[],"summary":"Public, read-only DNS setup for a shared domain (no authentication).","tags":["public"],"x-pc-sdk":false}},"/v1/public/domain-setup/{token}/export":{"get":{"description":"Same files as `GET .../domains/{domain_id}/dns-records/export`, under the share token. By default only records not yet verified; `all=true` for every record. 404 for an unknown, expired or revoked link. Shares the 60-per-minute IP limit.","operationId":"PublicDomainSetupController_export","parameters":[{"name":"token","required":true,"in":"path","description":"The share token from the link (43 characters, base64url).","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"}},{"name":"format","required":true,"in":"query","description":"File format: `bind` (a zone-file fragment, `text/dns`) or `csv`.","schema":{"type":"string","enum":["bind","csv"]},"example":"bind"},{"name":"zone","required":false,"in":"query","schema":{"type":"string","format":"hostname","example":"example.com"},"description":"BIND: the zone the names are relative to. Defaults to the detected zone, else the domain itself.","example":"example.com"},{"name":"all","required":false,"in":"query","schema":{"type":"boolean","default":false},"description":"Include records that already verify.","example":false}],"responses":{"200":{"description":"The file.","content":{"text/dns":{"schema":{"type":"string","example":"$ORIGIN example.com.\n$TTL 3600\n; dkim (required)\nproductcraft._domainkey.mail\t3600\tIN\tTXT\t\"v=DKIM1; k=rsa; p=MIIB...\" \"...IDAQAB\"\n"}},"text/csv":{"schema":{"type":"string","example":"type,name,value,priority,ttl,purpose,required\r\nTXT,productcraft._domainkey.mail.example.com,v=DKIM1; k=rsa; p=MIIB...,,3600,dkim,true\r\n"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`format` missing or not `bind`/`csv`, or `zone` is not the domain or one of its parents.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Unknown, expired or revoked link (`SHARE_LINK_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","SHARE_LINK_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 60 requests this minute from this IP (`RATE_LIMITED`). Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the next request is allowed.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[],"summary":"Download a shared domain's DNS records as a BIND zone fragment or a CSV (no authentication).","tags":["public"],"x-pc-sdk":false}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/dns-records/apply":{"post":{"description":"Reads the zone through the provider's API and plans every record the domain needs: `create`, `update` (only ever an SPF merge into an existing SPF record, shown with `before`/`after`) or `skip` (already there). `dry_run: true` returns the plan and changes nothing; `dry_run: false` applies exactly that plan, runs a DNS check straight away and records `setup_method = provider_api`. Only names at or under the domain are written, nothing is ever deleted, and Cloudflare records are DNS-only (not proxied). The recommended DMARC record (`p=none`) is included when `include_dmarc` is true (the default) and no DMARC policy applies to the domain yet; an existing policy is never touched. Any blocking conflict refuses the whole apply with 409. The token is used for this request only: it is never stored, logged, queued or returned; revoke it afterwards (`warnings` says so when it could see more than this zone). Applies are limited to one per domain every 10 seconds; dry runs are not limited.","operationId":"DnsApplyController_apply","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Required. Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`). A retry with the same key and body (the token is not part of the comparison) replays the first response instead of writing again, for 24 hours.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyDnsRecordsDto"}}}},"responses":{"200":{"description":"The plan (dry run), or the plan with each record's `result` and the post-apply DNS check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsApplyResultDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure; `Idempotency-Key` missing (`IDEMPOTENCY_KEY_REQUIRED`); `zone` not the domain or a parent (`INVALID_ZONE`); the provider rejected the token (`PROVIDER_TOKEN_REJECTED`), the token lacks DNS permissions (`PROVIDER_PERMISSION_DENIED`), or it cannot see a zone for the domain (`PROVIDER_ZONE_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","IDEMPOTENCY_KEY_REQUIRED","INVALID_ZONE","PROVIDER_TOKEN_REJECTED","PROVIDER_PERMISSION_DENIED","PROVIDER_ZONE_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"Missing `mail.update`, or the mail service is not enabled for the workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`DNS_CONFLICTS`: a blocking conflict (a second SPF record, a CNAME at the name, another DKIM key at our selector, other MX records at the MAIL FROM host or the domain, a merge over 10 SPF lookups). Nothing was written; the body carries the full `plan` and `conflicts`. Or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","DNS_CONFLICTS","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Applied less than 10 seconds ago (`RATE_LIMITED`). Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the next apply is allowed.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"502":{"description":"The provider failed or did not answer (`PROVIDER_UNAVAILABLE`, `PROVIDER_ERROR`). Nothing was written unless the plan items say so.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_GATEWAY","PROVIDER_UNAVAILABLE","PROVIDER_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Set up the domain's DNS records in one step with a short-lived Cloudflare or DigitalOcean API token.","tags":["domains"],"x-pc-sdk":{"resource":"domains.dnsRecords","method":"apply","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/domain-connect/start":{"post":{"description":"Returns a signed Domain Connect URL for the provider that hosts the domain's zone (Cloudflare, GoDaddy, IONOS, Vercel and the others that have onboarded ProductCraft's template). Open it in the browser: the user signs in at their provider and confirms, the provider writes the DKIM key at `productcraft._domainkey.<domain>` and the MAIL FROM records at `bounce.<domain>` (MX to the regional feedback host, SPF merged into any existing SPF there), and then redirects to `GET /v1/domain-connect/callback`, which records `setup_method = domain_connect`, checks the records and returns the user to the domain in the console. With `include_dmarc` and no DMARC policy in place yet, a second confirmation adds `v=DMARC1; p=none;` at `_dmarc.<domain>`. The URL is valid for 10 minutes and works once. ProductCraft never receives a DNS credential. For sending domains whose MAIL FROM label is `bounce` (the default). Not available while ProductCraft has Domain Connect switched off (`domain_connect.available` in `GET .../domains/lookup` says whether it is).","operationId":"DomainConnectController_start","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A replay returns the same URL, which still works only once.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartDomainConnectDto"}}}},"responses":{"200":{"description":"The signed apply URL to open in the browser.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainConnectStartDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure, or an id is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"Missing `mail.update`, or the mail service is not enabled for the workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"One-click setup is not possible for this domain; nothing was started. `DOMAIN_CONNECT_DISABLED`: ProductCraft has not switched Domain Connect on. `DOMAIN_CONNECT_UNAVAILABLE`: the DNS provider does not run Domain Connect or has not onboarded our template (`details.reason`: `no_record`, `settings_unreachable`, `template_not_onboarded` or `lookup_failed`; `details.provider_name`). `DOMAIN_CONNECT_NOT_SENDING`: a receive-only domain. `DOMAIN_CONNECT_MAIL_FROM_LABEL`: the MAIL FROM label is not `bounce` or MAIL FROM is off. `DKIM_KEY_MISSING`: no DKIM key to publish. Or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","DOMAIN_CONNECT_DISABLED","DOMAIN_CONNECT_UNAVAILABLE","DOMAIN_CONNECT_NOT_SENDING","DOMAIN_CONNECT_MAIL_FROM_LABEL","DKIM_KEY_MISSING","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Start one-click DNS setup at the domain's DNS provider (Domain Connect).","tags":["domains"],"x-pc-sdk":{"resource":"domains.domainConnect","method":"start","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/webhooks":{"get":{"deprecated":true,"operationId":"OutboundWebhookController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OutboundWebhookConfigDto"}}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List the workspace default + every per-domain override. Plaintext signing secrets are NOT returned — only the last-4-char hint. Mint or rotate via the secret endpoints to receive the plaintext (once). Deprecated: use `/webhooks/endpoints` instead. Responses carry `Deprecation: true` and `Sunset: Fri, 15 Jan 2027 00:00:00 GMT`; after 2027-01-15 this route returns 410. The slot is an ordinary endpoint (`legacy_slot` set) in `GET /webhooks/endpoints`.","tags":["outbound-webhooks"],"x-pc-sdk":false}},"/v1/workspaces/{workspace_id}/webhooks/default":{"get":{"deprecated":true,"operationId":"OutboundWebhookController_getDefault","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"Workspace-default config, or null if not configured.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundWebhookConfigDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get the workspace-default webhook config (returns null if unset). Deprecated: use `/webhooks/endpoints` instead. Responses carry `Deprecation: true` and `Sunset: Fri, 15 Jan 2027 00:00:00 GMT`; after 2027-01-15 this route returns 410. The slot is an ordinary endpoint (`legacy_slot` set) in `GET /webhooks/endpoints`.","tags":["outbound-webhooks"],"x-pc-sdk":false},"put":{"deprecated":true,"operationId":"OutboundWebhookController_upsertDefault","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertOutboundWebhookDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundWebhookConfigWithSecretDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure (bad URL or event-type set).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"URL failed SSRF + reachability checks at config time.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create or replace the workspace-default outbound webhook. Returns the plaintext signing secret ONCE — store it now. Deprecated: use `/webhooks/endpoints` instead. Responses carry `Deprecation: true` and `Sunset: Fri, 15 Jan 2027 00:00:00 GMT`; after 2027-01-15 this route returns 410. The slot is an ordinary endpoint (`legacy_slot` set) in `GET /webhooks/endpoints`.","tags":["outbound-webhooks"],"x-pc-sdk":false},"delete":{"deprecated":true,"operationId":"OutboundWebhookController_deleteDefault","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Workspace-default webhook deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete the workspace-default webhook config. Deprecated: use `/webhooks/endpoints` instead. Responses carry `Deprecation: true` and `Sunset: Fri, 15 Jan 2027 00:00:00 GMT`; after 2027-01-15 this route returns 410. The slot is an ordinary endpoint (`legacy_slot` set) in `GET /webhooks/endpoints`.","tags":["outbound-webhooks"],"x-pc-sdk":false}},"/v1/workspaces/{workspace_id}/webhooks/default/rotate-secret":{"post":{"deprecated":true,"operationId":"OutboundWebhookController_rotateDefaultSecret","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundWebhookConfigWithSecretDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No webhook configured to rotate.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Rotate the workspace-default webhook signing secret. Previous secret remains valid for 24h. Plaintext returned once. Deprecated: use `/webhooks/endpoints` instead. Responses carry `Deprecation: true` and `Sunset: Fri, 15 Jan 2027 00:00:00 GMT`; after 2027-01-15 this route returns 410. The slot is an ordinary endpoint (`legacy_slot` set) in `GET /webhooks/endpoints`.","tags":["outbound-webhooks"],"x-pc-sdk":false}},"/v1/workspaces/{workspace_id}/webhooks/domains/{domain_id}":{"get":{"deprecated":true,"operationId":"OutboundWebhookController_getDomain","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"Per-domain override, or null if not configured (an unset override is not a 404).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundWebhookConfigDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get the per-domain webhook override (returns null if unset). Deprecated: use `/webhooks/endpoints` instead. Responses carry `Deprecation: true` and `Sunset: Fri, 15 Jan 2027 00:00:00 GMT`; after 2027-01-15 this route returns 410. The slot is an ordinary endpoint (`legacy_slot` set) in `GET /webhooks/endpoints`.","tags":["outbound-webhooks"],"x-pc-sdk":false},"put":{"deprecated":true,"operationId":"OutboundWebhookController_upsertDomain","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertOutboundWebhookDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundWebhookConfigWithSecretDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure (bad URL or event-type set).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"URL failed SSRF + reachability checks at config time.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create or replace the per-domain webhook override. Returns the plaintext signing secret ONCE — store it now. Deprecated: use `/webhooks/endpoints` instead. Responses carry `Deprecation: true` and `Sunset: Fri, 15 Jan 2027 00:00:00 GMT`; after 2027-01-15 this route returns 410. The slot is an ordinary endpoint (`legacy_slot` set) in `GET /webhooks/endpoints`.","tags":["outbound-webhooks"],"x-pc-sdk":false},"delete":{"deprecated":true,"operationId":"OutboundWebhookController_deleteDomain","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Per-domain webhook override deleted. Idempotent: also 204 when no override is configured, so there is no 404.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete the per-domain webhook override. Deprecated: use `/webhooks/endpoints` instead. Responses carry `Deprecation: true` and `Sunset: Fri, 15 Jan 2027 00:00:00 GMT`; after 2027-01-15 this route returns 410. The slot is an ordinary endpoint (`legacy_slot` set) in `GET /webhooks/endpoints`.","tags":["outbound-webhooks"],"x-pc-sdk":false}},"/v1/workspaces/{workspace_id}/webhooks/domains/{domain_id}/rotate-secret":{"post":{"deprecated":true,"operationId":"OutboundWebhookController_rotateDomainSecret","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundWebhookConfigWithSecretDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No per-domain webhook configured to rotate.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Rotate the per-domain webhook signing secret. Previous secret remains valid for 24h. Plaintext returned once. Deprecated: use `/webhooks/endpoints` instead. Responses carry `Deprecation: true` and `Sunset: Fri, 15 Jan 2027 00:00:00 GMT`; after 2027-01-15 this route returns 410. The slot is an ordinary endpoint (`legacy_slot` set) in `GET /webhooks/endpoints`.","tags":["outbound-webhooks"],"x-pc-sdk":false}},"/v1/workspaces/{workspace_id}/webhooks/attempts":{"get":{"operationId":"OutboundWebhookController_listAttempts","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","description":"Page size, 1–200 (default 50). Page further back with `cursor`.","schema":{"minimum":1,"maximum":200,"default":50,"example":50,"type":"integer"},"example":50},{"name":"cursor","required":false,"in":"query","description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","schema":{"type":"string"},"example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"},{"name":"event_id","required":false,"in":"query","description":"Only the attempts for this event (`evt_<uuid>`).","schema":{"pattern":"^evt_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"string"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"endpoint_id","required":false,"in":"query","description":"Only the attempts made to this endpoint.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWebhookAttemptsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid `limit`, `cursor`, `event_id` or `endpoint_id`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delivery attempts across all of this workspace's webhook endpoints, newest first, cursor-paginated, optionally for one event or one endpoint. Includes status code, latency, response body (truncated to 1KB), and error if any.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.attempts","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/webhooks/event-types":{"get":{"description":"Each type with a plain description, its group and an example `data` object (what \"Send test\" delivers).","operationId":"WebhooksController_mail_workspace_listEventTypes","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWebhookEventTypesResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List the events an endpoint can subscribe to.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.eventTypes","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/webhooks/endpoints":{"get":{"description":"At most 10, so this is always one page. Signing secrets are never returned here, only their last 4 characters.","operationId":"WebhooksController_mail_workspace_listEndpoints","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWebhookEndpointsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"The scope id in the path is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List webhook endpoints, oldest first.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.endpoints","method":"list","bind":["workspace_id"],"paginated":true}},"post":{"description":"Deliveries are signed with the Standard Webhooks headers `webhook-id`, `webhook-timestamp` and `webhook-signature` (`v1,<base64 HMAC-SHA256 of \"<id>.<timestamp>.<body>\">`); the returned `whsec_…` secret works unchanged with any Standard Webhooks library. Failed deliveries are retried after 1 min, 5 min, 30 min, 2 h, 6 h and 24 h.","operationId":"WebhooksController_mail_workspace_createEndpoint","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1-256 chars, `[A-Za-z0-9_-:]`) that makes a retry of this request safe for 24 hours. The same key with a different body returns 409 `IDEMPOTENCY_KEY_REUSE`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookEndpointDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointWithSecretDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure: URL not https with a public host, or an unknown event type (`WEBHOOK_EVENT_TYPE_UNKNOWN`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","WEBHOOK_EVENT_TYPE_UNKNOWN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"Already 10 endpoints (`WEBHOOK_ENDPOINT_LIMIT`), or Idempotency-Key reused with a different body (`IDEMPOTENCY_KEY_REUSE`). Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","WEBHOOK_ENDPOINT_LIMIT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"The URL points at a private, loopback or internal address.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Add a webhook endpoint. Returns its signing secret once.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.endpoints","method":"create","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/webhooks/endpoints/{endpoint_id}":{"get":{"description":"The endpoint's URL, subscription, on/off state, failure streak and the last 4 characters of its signing secret. The full secret is only returned when the endpoint is created or its secret is rotated.","operationId":"WebhooksController_mail_workspace_getEndpoint","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"endpoint_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the endpoint.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`endpoint_id` is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such endpoint here (`WEBHOOK_ENDPOINT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","WEBHOOK_ENDPOINT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get one webhook endpoint (without its secret).","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.endpoints","method":"retrieve","bind":["workspace_id"],"paginated":false}},"patch":{"description":"Only the fields sent change. `enabled: true` (or a new URL) also clears an automatic disable. Switching off cancels queued retries. The secret is unchanged; rotate it with `POST …/rotate-secret`.","operationId":"WebhooksController_mail_workspace_updateEndpoint","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"endpoint_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the endpoint.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1-256 chars, `[A-Za-z0-9_-:]`) that makes a retry of this request safe for 24 hours. The same key with a different body returns 409 `IDEMPOTENCY_KEY_REUSE`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookEndpointDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure, or `endpoint_id` is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such endpoint here (`WEBHOOK_ENDPOINT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","WEBHOOK_ENDPOINT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Idempotency-Key reused with a different body (`IDEMPOTENCY_KEY_REUSE`). Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"The new URL points at a private, loopback or internal address.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Change a webhook endpoint: URL, description, events, on/off.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.endpoints","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"description":"Queued retries are dropped. Its past attempts stay in the event log until the events expire.","operationId":"WebhooksController_mail_workspace_deleteEndpoint","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"endpoint_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the endpoint.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`endpoint_id` is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such endpoint here (`WEBHOOK_ENDPOINT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","WEBHOOK_ENDPOINT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete a webhook endpoint.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.endpoints","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/webhooks/endpoints/{endpoint_id}/rotate-secret":{"post":{"description":"For `grace_hours` (default 24) the previous secret keeps signing too: `webhook-signature` then lists one `v1,` signature per secret, so receivers can switch over without dropping a delivery.","operationId":"WebhooksController_mail_workspace_rotateSecret","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"endpoint_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the endpoint.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1-256 chars, `[A-Za-z0-9_-:]`) that makes a retry of this request safe for 24 hours. The same key with a different body returns 409 `IDEMPOTENCY_KEY_REUSE`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotateWebhookSecretDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointWithSecretDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`grace_hours` out of range, or `endpoint_id` is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such endpoint here (`WEBHOOK_ENDPOINT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","WEBHOOK_ENDPOINT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Idempotency-Key reused with a different body (`IDEMPOTENCY_KEY_REUSE`). Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Rotate the signing secret. The new one is returned once.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.endpoints","method":"rotateSecret","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/webhooks/endpoints/{endpoint_id}/test":{"post":{"description":"Delivers the catalogue example of `event_type`, signed like any delivery, with `\"test\": true` in the body. Works while the endpoint is switched off or not subscribed to that type, is logged in the event log, and is never retried or counted toward an automatic disable. Waits up to 15 s for your receiver.","operationId":"WebhooksController_mail_workspace_sendTest","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"endpoint_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the endpoint.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1-256 chars, `[A-Za-z0-9_-:]`) that makes a retry of this request safe for 24 hours. The same key with a different body returns 409 `IDEMPOTENCY_KEY_REUSE`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendWebhookTestDto"}}}},"responses":{"200":{"description":"The attempt, successful or not.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryAttemptDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Unknown `event_type`, or `endpoint_id` is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such endpoint here (`WEBHOOK_ENDPOINT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","WEBHOOK_ENDPOINT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Idempotency-Key reused with a different body (`IDEMPOTENCY_KEY_REUSE`). Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send a test event to this endpoint now and return the result.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.endpoints","method":"test","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/webhooks/events":{"get":{"description":"Every event logged while at least one endpoint existed, with the latest state per endpoint and when the next retry is due.","operationId":"WebhooksController_mail_workspace_listEvents","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"type","required":false,"in":"query","description":"Only these types. Repeat the parameter or comma-separate.","schema":{"type":"array","items":{"type":"string","enum":["email.sent","email.delivered","email.delivery_delayed","email.bounced","email.complained","email.failed","email.suppressed","email.skipped","email.scheduled","email.canceled","email.opened","email.clicked","email.received","domain.created","domain.updated","domain.verified","domain.deleted","suppression.added","suppression.removed","sending_defaults.updated","contact.created","contact.updated","contact.deleted"]}},"example":["email.sent"]},{"name":"endpoint_id","required":false,"in":"query","description":"Only events sent (or queued) to this endpoint.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"status","required":false,"in":"query","description":"Only events in this delivery status.","schema":{"$ref":"#/components/schemas/WebhookEventStatus"},"example":"pending"},{"name":"created_after","required":false,"in":"query","description":"Only events created at or after this instant.","schema":{"format":"date-time","type":"string"},"example":"2026-11-01T00:00:00Z"},{"name":"created_before","required":false,"in":"query","description":"Only events created before this instant.","schema":{"format":"date-time","type":"string"},"example":"2026-11-01T00:00:00Z"},{"name":"limit","required":false,"in":"query","description":"Page size.","schema":{"minimum":1,"maximum":100,"default":20,"type":"integer"},"example":20},{"name":"cursor","required":false,"in":"query","description":"The previous page's `pagination.next_cursor`.","schema":{"type":"string"},"example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"},{"name":"email_id","required":false,"in":"query","description":"Only events about this email (`outbound_message.id`).","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":false,"in":"query","description":"Only events about this domain.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWebhookEventsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid filter value or cursor.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List webhook events, newest first (kept for 30 days).","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.events","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/webhooks/events/{event_id}":{"get":{"description":"The event as it was sent (`type`, `data`) and every delivery attempt to every endpoint, with its trigger, HTTP status, error and the start of the response body. Use it to debug a receiver, then `replay` to send it again.","operationId":"WebhooksController_mail_workspace_getEvent","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"event_id","required":true,"in":"path","description":"The event id, `evt_<uuid>`.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEventDetailDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`event_id` is not `evt_<uuid>`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such event here (`WEBHOOK_EVENT_NOT_FOUND`); events are kept for 30 days.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","WEBHOOK_EVENT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get one webhook event with every delivery attempt.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.events","method":"retrieve","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/webhooks/events/{event_id}/replay":{"post":{"description":"Same body and `webhook-id`, freshly signed, to every switched-on endpoint that receives this event type now, or only to `endpoint_id`. Waits for the receivers (up to 15 s each) and returns the attempts. A success cancels a retry still queued for that endpoint.","operationId":"WebhooksController_mail_workspace_replay","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"event_id","required":true,"in":"path","description":"The event id, `evt_<uuid>`.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"}},{"name":"endpoint_id","required":false,"in":"query","description":"Send to this endpoint only.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1-256 chars, `[A-Za-z0-9_-:]`) that makes a retry of this request safe for 24 hours. The same key with a different body returns 409 `IDEMPOTENCY_KEY_REUSE`.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplayWebhookEventResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`event_id` is not `evt_<uuid>`, or `endpoint_id` is not a UUID.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such event here (`WEBHOOK_EVENT_NOT_FOUND`); events are kept for 30 days. Or No such endpoint here (`WEBHOOK_ENDPOINT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","WEBHOOK_EVENT_NOT_FOUND","WEBHOOK_ENDPOINT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`endpoint_id` is switched off or does not receive this event type (`WEBHOOK_ENDPOINT_NOT_SUBSCRIBED`), or Idempotency-Key reused with a different body (`IDEMPOTENCY_KEY_REUSE`). Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","WEBHOOK_ENDPOINT_NOT_SUBSCRIBED","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send a logged event again, to its endpoints or to one endpoint.","tags":["outbound-webhooks"],"x-pc-sdk":{"resource":"webhooks.events","method":"replay","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/stats":{"get":{"description":"Outbound sent, delivered, bounced, complained, deferred, suppressed and unconfirmed counts in the window, the deliverability, bounce and complaint rates, domain totals, the last send time and a daily sent series. For ranges, buckets, filters and a per-domain breakdown use `GET /emails/metrics`; the rates here use its definitions.\n\n`delivered` means the recipient's mail server confirmed the message; `unconfirmed` means the message was handed off and nothing came back either way, which is not the same as delivered. Days are UTC. Rates are 0 to 1, or null when not measured: delivery and complaints are only reported for mail with delivery tracking. Outbound messages are kept for 30 days, so 30d is the longest window. Cached for up to 60 seconds (`generated_at`).","operationId":"WorkspaceStatsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","description":"Workspace id.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"window","required":false,"in":"query","description":"Window for `in_window` and the length of `series`, in UTC days ending today. 30d is the maximum because outbound messages are kept for 30 days.","schema":{"default":"30d","example":"30d","enum":["1d","7d","30d"],"type":"string"},"example":"30d"}],"responses":{"200":{"description":"Mail stats.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailWorkspaceStatsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`window` is not one of 1d, 7d, 30d.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"Caller lacks `mail.message.read` on the workspace (including non-members), or Mail is not enabled on it (`SERVICE_NOT_ENABLED`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN","SERVICE_NOT_ENABLED"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Mail stats for a workspace","tags":["stats"],"x-pc-sdk":{"resource":"stats","method":"retrieve","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/emails/metrics":{"get":{"description":"Outbound email counts and rates over a range of up to 30 days, in hourly or daily buckets in your time zone, optionally per sending domain, filtered by domain, API key or source. Read-only.\n\n- **Emails** (`sent`): messages that left the queue.\n- **Deliverability rate**: delivered / emails sent with delivery tracking. Emails sent before delivery tracking started, or through a custom SMTP relay, are confirmed at hand-off only, so for them `delivered` is not measured and the rate is `null` (`measured.delivery = false`), never 0.\n- **Bounce rate**: bounced / emails. Suppressed recipients never count.\n- **Complaint rate**: complained / delivered, from mailbox providers' feedback loops.\n\nRates are numbers from 0 to 1, or `null` when unmeasured or when the denominator is zero. Template test sends are excluded. Cached for up to 60 seconds.","operationId":"EmailMetricsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","description":"Workspace id.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"start_date","required":false,"in":"query","description":"Start of the range, inclusive. ISO 8601. A bare date (`2026-10-12`) is that calendar day in `timezone`; a date-time without an offset is a wall time in `timezone`; one with `Z` or an offset is that instant. Default: midnight six days before today, so the default range is the last 7 days including today. Must be within the 30-day message retention.","schema":{"maxLength":40,"example":"2026-10-06","type":"string"},"example":"2026-10-06"},{"name":"end_date","required":false,"in":"query","description":"End of the range, exclusive. ISO 8601. A bare date (`2026-10-12`) is that calendar day in `timezone`; a date-time without an offset is a wall time in `timezone`; one with `Z` or an offset is that instant. A bare date includes that whole day. Default: now. At most 30 days after `start_date`.","schema":{"maxLength":40,"example":"2026-10-12T15:00:00Z","type":"string"},"example":"2026-10-12T15:00:00Z"},{"name":"timezone","required":false,"in":"query","description":"IANA time zone the buckets and bare dates follow (DST-aware). Default `UTC`.","schema":{"maxLength":64,"default":"UTC","example":"Europe/Lisbon","type":"string"},"example":"Europe/Lisbon"},{"name":"granularity","required":false,"in":"query","description":"Bucket width. Default `hourly` when the range is 2 days or less, otherwise `daily`. `hourly` is limited to ranges of 7 days or less.","schema":{"example":"daily","enum":["hourly","daily"],"type":"string"},"example":"daily"},{"name":"domain_id","required":false,"in":"query","description":"Only mail sent from these domains (`domain.id`). Repeat the parameter (with or without `[]`) or comma-separate the values; at most 100.","schema":{"maxItems":100,"example":["3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b"],"type":"array","items":{"type":"string","format":"uuid"}},"example":["3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b"]},{"name":"api_key_id","required":false,"in":"query","description":"Only mail sent with this Platform API Key. Keys are recorded from 2026-10-12; older mail has none.","schema":{"format":"uuid","example":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d","type":"string"},"example":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"},{"name":"source","required":false,"in":"query","description":"Only mail sent this way: `api_key` (a Platform API Key), `dashboard` (a signed-in person, in the console or through MCP), `platform` (in-cluster product mail, and every message sent before 2026-10-12). Template test sends are never counted.","schema":{"example":"api_key","enum":["api_key","dashboard","platform"],"type":"string"},"example":"api_key"},{"name":"dimensions","required":false,"in":"query","description":"How `data` is broken down. `period`: one item per bucket (dense, zero-filled). `domain`: one item per sending domain. Both: one item per bucket and domain. Default `period`. Repeat the parameter (with or without `[]`) or comma-separate the values.","schema":{"example":["period"],"type":"array","items":{"type":"string","enum":["period","domain"]}},"example":["period"]}],"responses":{"200":{"description":"Email metrics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailMetricsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A parameter is invalid: `domain_id` or `api_key_id` is not a UUID; more than 100 `domain_id`; an unknown `timezone`, `granularity`, `source` or dimension; a date that does not parse; `end_date` not after `start_date`; a range longer than 30 days or starting before the 30-day retention; or `granularity=hourly` over more than 7 days. The reason is in `message`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"No valid credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"Caller lacks `mail.message.read` on the workspace (including non-members), or Mail is not enabled on it (`SERVICE_NOT_ENABLED`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN","SERVICE_NOT_ENABLED"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Email metrics for a workspace","tags":["metrics"],"x-pc-sdk":{"resource":"emails","method":"metrics","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/smtp-config":{"get":{"operationId":"SmtpConfigController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSmtpConfigResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get the workspace-default SMTP config (returns null if unset). Per-domain overrides live under /workspaces/:id/domains/:domainId/smtp-config.","tags":["smtp-config"],"x-pc-sdk":{"resource":"smtpConfig","method":"retrieve","bind":["workspace_id"],"paginated":false}},"put":{"operationId":"SmtpConfigController_upsert","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSmtpConfigDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmtpConfigDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure or username/password mismatch.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create or update the workspace-default SMTP config (resets verification)","tags":["smtp-config"],"x-pc-sdk":{"resource":"smtpConfig","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"operationId":"SmtpConfigController_delete","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Workspace-default SMTP config deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No SMTP config to delete","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Revert the workspace to ProductCraft Mail's own sending","tags":["smtp-config"],"x-pc-sdk":{"resource":"smtpConfig","method":"reset","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/smtp-config/verify":{"post":{"operationId":"SmtpConfigController_verifyTransient","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifySmtpConfigDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmtpVerifyResultDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure on the request body.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Test arbitrary SMTP creds without persisting","tags":["smtp-config"],"x-pc-sdk":{"resource":"smtpConfig","method":"verify","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/smtp-config/verify-saved":{"post":{"operationId":"SmtpConfigController_verifySaved","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmtpVerifyResultDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No SMTP config saved","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Test the persisted workspace-default SMTP config; updates status","tags":["smtp-config"],"x-pc-sdk":{"resource":"smtpConfig","method":"verifySaved","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/smtp-configs":{"get":{"operationId":"SmtpConfigListController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSmtpConfigsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List every SMTP config in the workspace (default + per-domain overrides)","tags":["smtp-config"],"x-pc-sdk":{"resource":"smtpConfig","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/smtp-config":{"get":{"operationId":"DomainSmtpConfigController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSmtpConfigResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get the per-domain SMTP override (returns null if unset; the workspace default applies in that case).","tags":["smtp-config"],"x-pc-sdk":{"resource":"domains.smtpConfig","method":"retrieve","bind":["workspace_id"],"paginated":false}},"put":{"operationId":"DomainSmtpConfigController_upsert","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSmtpConfigDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmtpConfigDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure or username/password mismatch.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create or update the per-domain SMTP override (resets verification)","tags":["smtp-config"],"x-pc-sdk":{"resource":"domains.smtpConfig","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"operationId":"DomainSmtpConfigController_delete","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Per-domain override deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No per-domain override to delete","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Drop the per-domain override; sends from this domain fall back to the workspace default (or ProductCraft Mail's own sending).","tags":["smtp-config"],"x-pc-sdk":{"resource":"domains.smtpConfig","method":"reset","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/smtp-config/verify-saved":{"post":{"operationId":"DomainSmtpConfigController_verifySaved","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmtpVerifyResultDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No per-domain override saved","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Test the per-domain SMTP override; updates status","tags":["smtp-config"],"x-pc-sdk":{"resource":"domains.smtpConfig","method":"verifySaved","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/suppression":{"post":{"operationId":"SuppressionController_add","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddSuppressionDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuppressionEntryDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid payload (missing or malformed email).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Email address rejected as invalid by the service layer.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Add an email to the workspace suppression list","tags":["suppression"],"x-pc-sdk":{"resource":"suppression","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"SuppressionController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"},{"name":"search","required":false,"in":"query","schema":{"type":"string","maxLength":200},"description":"Case-insensitive substring match on the suppressed email address."},{"name":"source","required":false,"in":"query","schema":{"type":"string","enum":["manual","bounce","complaint"]},"description":"Filter by where the row originated. Unrecognised values are rejected with a 400.","example":"manual"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSuppressionResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid cursor, search term, or source filter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List suppressed recipients in the workspace (most-recent first), cursor-paginated.","tags":["suppression"],"x-pc-sdk":{"resource":"suppression","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/suppression/{email}":{"delete":{"operationId":"SuppressionController_remove","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"email","required":true,"in":"path","description":"The suppressed address (URL-encoded).","schema":{"type":"string","format":"email"}}],"responses":{"204":{"description":"Suppression removed.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Email is not on this workspace suppression list.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Remove an address from the workspace suppression list.","tags":["suppression"],"x-pc-sdk":{"resource":"suppression","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/mailboxes":{"post":{"operationId":"MailboxController_createMailbox","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMailboxDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure (invalid local part, retention out of range).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"Caller lacks `mail.create` permission, or workspace has not enabled the `mail` service.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Domain not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Mailbox local-part already exists on this domain, or the domain is not yet verified, or `IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different body or route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Local part or retention rejected by service-layer validation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create a mailbox under a verified domain. Local-part + domain combination must be globally unique.","tags":["mailboxes"],"x-pc-sdk":{"resource":"mailboxes","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"MailboxController_listMailboxes","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","description":"Page size, 1–100.","schema":{"minimum":1,"maximum":100,"default":20,"example":20,"type":"integer"},"example":20},{"name":"cursor","required":false,"in":"query","description":"Opaque pagination cursor","schema":{"type":"string"},"example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMailboxesResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"Caller lacks `mail.read` permission, or workspace has not enabled the `mail` service.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List mailboxes in this workspace. 20 per page by default (max 200) — paginate with the cursor returned in `pagination.next_cursor` while `pagination.has_more` is true.","tags":["mailboxes"],"x-pc-sdk":{"resource":"mailboxes","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/mailboxes/{id}":{"get":{"operationId":"MailboxController_getMailbox","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the mailboxe.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Mailbox not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get one mailbox by id.","tags":["mailboxes"],"x-pc-sdk":{"resource":"mailboxes","method":"retrieve","bind":["workspace_id"],"paginated":false}},"patch":{"operationId":"MailboxController_updateMailbox","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the mailboxe.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMailboxDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure or invalid status transition.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Mailbox not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Retention or status rejected by service-layer validation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Update mailbox display name, retention, or status. Status transitions are restricted (active ↔ suspended; archived is terminal).","tags":["mailboxes"],"x-pc-sdk":{"resource":"mailboxes","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"operationId":"MailboxController_deleteMailbox","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the mailboxe.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Mailbox soft-deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Mailbox not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Soft-delete a mailbox: its status becomes `disabled` and it stops accepting new mail; existing messages are kept until retention purges them, and `PATCH` with `status: active` restores it. A deleted mailbox no longer blocks deleting its domain, and deleting the domain erases it and its remaining mail.","tags":["mailboxes"],"x-pc-sdk":{"resource":"mailboxes","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/mailboxes/{id}/messages":{"get":{"operationId":"MessageController_listMessages","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the mailboxe.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"from","required":false,"in":"query","description":"Filter by From address (substring match)","schema":{"type":"string"}},{"name":"subject","required":false,"in":"query","description":"Filter by subject (substring match)","schema":{"type":"string"}},{"name":"since","required":false,"in":"query","description":"Only include messages received on or after this ISO-8601 timestamp.","schema":{"format":"date-time","example":"2026-04-01T00:00:00Z","type":"string"},"example":"2026-04-01T00:00:00Z"},{"name":"until","required":false,"in":"query","description":"Only include messages received on or before this ISO-8601 timestamp.","schema":{"format":"date-time","example":"2026-05-01T00:00:00Z","type":"string"},"example":"2026-05-01T00:00:00Z"},{"name":"unread","required":false,"in":"query","description":"Filter to only unread (true) or only read (false) messages","schema":{"type":"boolean"},"example":true},{"name":"limit","required":false,"in":"query","description":"Page size, 1–100.","schema":{"minimum":1,"maximum":100,"default":20,"example":20,"type":"integer"},"example":20},{"name":"cursor","required":false,"in":"query","description":"Opaque pagination cursor","schema":{"type":"string"},"example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMessagesResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid filter or cursor.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Mailbox not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List messages in a mailbox","tags":["messages"],"x-pc-sdk":{"resource":"mailboxes.messages","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/mailboxes/{id}/messages/{mid}":{"get":{"operationId":"MessageController_getMessage","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the mailboxe.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"mid","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the message in the mailbox.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageDetailDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Message not found","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a single message (metadata + attachment manifest; `body_preview` is null without `mail.message.body.read`). Use /:mid/raw for content.","tags":["messages"],"x-pc-sdk":{"resource":"mailboxes.messages","method":"retrieve","bind":["workspace_id"],"paginated":false}},"delete":{"operationId":"MessageController_deleteMessage","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the mailboxe.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"mid","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the message in the mailbox.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Message soft-deleted","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Message not found","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Soft-delete a message","tags":["messages"],"x-pc-sdk":{"resource":"mailboxes.messages","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/mailboxes/{id}/messages/{mid}/raw":{"get":{"operationId":"MessageController_getRaw","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the mailboxe.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"mid","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the message in the mailbox.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"Raw RFC5322 message stream (`Content-Disposition: attachment`, `.eml`).","content":{"message/rfc822":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"Policy denies `mail.message.body.read`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Message not found","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Stream the raw RFC5322 .eml for a message. Gated by `mail.message.body.read` (admin+ by default; not granted to plain members) — the outbound lane's /messages/:id/body action.","tags":["messages"],"x-pc-sdk":{"resource":"mailboxes.messages","method":"raw","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/mailboxes/{id}/messages/{mid}/attachments/{position}":{"get":{"operationId":"MessageController_getAttachment","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the mailboxe.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"mid","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the message in the mailbox.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"position","required":true,"in":"path","schema":{"type":"number"},"description":"Position of the attachment in the message, starting at 0.","example":0}],"responses":{"200":{"description":"Binary attachment stream. `Content-Type` reflects the stored attachment media type; `Content-Disposition: attachment`.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"Policy denies `mail.message.body.read`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Attachment not found","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Stream a single attachment by its position. Gated by `mail.message.body.read`: an attachment is message content, and /:mid already names it without handing over the bytes.","tags":["messages"],"x-pc-sdk":{"resource":"mailboxes.messages.attachments","method":"retrieve","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/mailboxes/{id}/messages/{mid}/read":{"post":{"operationId":"MessageController_markRead","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the mailboxe.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"mid","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the message in the mailbox.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Marked read","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Message not found","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Mark a message as read","tags":["messages"],"x-pc-sdk":{"resource":"mailboxes.messages","method":"read","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/received":{"get":{"description":"Newest first, cursor-paged, deleted email excluded. Filters combine with AND: `q` (sender, subject, envelope recipient or To address as a substring; or an exact id or Message-ID), `mailbox_id`, `domain_id`, `received_after` / `received_before` (at most 30 days apart), `spam`, `unread`. `GET /received/export` takes exactly the same filters and returns the same rows. No body content.","operationId":"ReceivedController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"q","required":false,"in":"query","description":"Free-text search, case-insensitive. Matches a substring of the sender, the subject, the envelope recipient or a To address, or exactly a received email id (uuid) or its RFC 822 Message-ID (with or without the angle brackets).","schema":{"maxLength":200,"example":"invoice","type":"string"},"example":"invoice"},{"name":"mailbox_id","required":false,"in":"query","description":"Only email received by this mailbox.","schema":{"format":"uuid","example":"5c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f","type":"string"},"example":"5c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f"},{"name":"domain_id","required":false,"in":"query","description":"Only email received by mailboxes on this domain (`domain.id`).","schema":{"format":"uuid","example":"3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b","type":"string"},"example":"3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b"},{"name":"received_after","required":false,"in":"query","description":"Only email received at or after this instant. With `received_before`, the window may span at most 30 days.","schema":{"format":"date-time","example":"2026-10-05T00:00:00Z","type":"string"},"example":"2026-10-05T00:00:00Z"},{"name":"received_before","required":false,"in":"query","description":"Only email received before this instant. Without `received_after`, the window is the 30 days before it.","schema":{"format":"date-time","example":"2026-10-12T00:00:00Z","type":"string"},"example":"2026-10-12T00:00:00Z"},{"name":"spam","required":false,"in":"query","description":"`true`: only email the spam filter quarantined (verdict `junk` or `reject`). `false`: only email it did not. Omit for both.","schema":{"example":false,"type":"boolean"},"example":false},{"name":"unread","required":false,"in":"query","description":"`true`: only unread email. `false`: only email already marked read. Omit for both.","schema":{"example":true,"type":"boolean"},"example":true},{"name":"limit","required":false,"in":"query","description":"Page size, 1–100","schema":{"default":20,"example":20,"type":"integer"},"example":20},{"name":"cursor","required":false,"in":"query","description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","schema":{"type":"string"},"example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListReceivedEmailsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid filter or cursor: a malformed uuid, boolean or date-time, `q` over 200 characters, `received_after` not earlier than `received_before`, or a window wider than 30 days. The reason is in `message`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The policy does not grant `mail.list` on every mailbox, or Mail is not enabled for this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List received email across every mailbox in the workspace","tags":["received"],"x-pc-sdk":{"resource":"received","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/received/export":{"get":{"description":"Columns: id, received_at, mailbox, from, to (`; `-separated), subject, spam_verdict, spf, dkim, dmarc, size_bytes, attachments (count). No body content. A cell starting with `=`, `+`, `-` or `@` is prefixed with `'` so a spreadsheet does not run it as a formula. A rejected filter (400) does not count against the hourly cap, which is separate from the sent-email export's.","operationId":"ReceivedController_exportCsv","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"q","required":false,"in":"query","description":"Free-text search, case-insensitive. Matches a substring of the sender, the subject, the envelope recipient or a To address, or exactly a received email id (uuid) or its RFC 822 Message-ID (with or without the angle brackets).","schema":{"maxLength":200,"example":"invoice","type":"string"},"example":"invoice"},{"name":"mailbox_id","required":false,"in":"query","description":"Only email received by this mailbox.","schema":{"format":"uuid","example":"5c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f","type":"string"},"example":"5c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f"},{"name":"domain_id","required":false,"in":"query","description":"Only email received by mailboxes on this domain (`domain.id`).","schema":{"format":"uuid","example":"3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b","type":"string"},"example":"3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b"},{"name":"received_after","required":false,"in":"query","description":"Only email received at or after this instant. With `received_before`, the window may span at most 30 days.","schema":{"format":"date-time","example":"2026-10-05T00:00:00Z","type":"string"},"example":"2026-10-05T00:00:00Z"},{"name":"received_before","required":false,"in":"query","description":"Only email received before this instant. Without `received_after`, the window is the 30 days before it.","schema":{"format":"date-time","example":"2026-10-12T00:00:00Z","type":"string"},"example":"2026-10-12T00:00:00Z"},{"name":"spam","required":false,"in":"query","description":"`true`: only email the spam filter quarantined (verdict `junk` or `reject`). `false`: only email it did not. Omit for both.","schema":{"example":false,"type":"boolean"},"example":false},{"name":"unread","required":false,"in":"query","description":"`true`: only unread email. `false`: only email already marked read. Omit for both.","schema":{"example":true,"type":"boolean"},"example":true}],"responses":{"200":{"description":"text/csv stream: one header row, then one row per email. Content-Disposition: attachment.","content":{"text/csv":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid filter or cursor: a malformed uuid, boolean or date-time, `q` over 200 characters, `received_after` not earlier than `received_before`, or a window wider than 30 days. The reason is in `message`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The policy does not grant `mail.list` on every mailbox, or Mail is not enabled for this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"Another received-email export is already running, or this workspace has hit the hourly cap (5). Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Stream the filtered received email as CSV. Same filters as GET /received. Rate-limited 1 concurrent + 5/hour per workspace.","tags":["received"],"x-pc-sdk":{"resource":"received","method":"export","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/received/{id}":{"get":{"description":"Metadata, the authentication results, the envelope recipient and the attachment manifest. `body_preview` is null without `mail.message.body.read`; the full message is at `/received/{id}/raw`.","operationId":"ReceivedController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","description":"Received email id.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceivedEmailDetailDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`id` is not a uuid.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The policy does not grant `mail.read` on every mailbox.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"No such email in this workspace (or it was deleted).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get one received email","tags":["received"],"x-pc-sdk":{"resource":"received","method":"retrieve","bind":["workspace_id"],"paginated":false}},"delete":{"description":"Soft delete: it disappears from every list at once; retention purges the stored message later.","operationId":"ReceivedController_remove","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","description":"Received email id.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`id` is not a uuid.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The policy does not grant `mail.delete` on every mailbox.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"No such email in this workspace (or it was already deleted).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete a received email","tags":["received"],"x-pc-sdk":{"resource":"received","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/received/{id}/raw":{"get":{"description":"Every header, the full body and every attachment inline. Gated by `mail.message.body.read` (admin and up by default), like `/mailboxes/{id}/messages/{mid}/raw`.","operationId":"ReceivedController_getRaw","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","description":"Received email id.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"Raw RFC 5322 message stream (`Content-Disposition: attachment`, `.eml`).","content":{"message/rfc822":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`id` is not a uuid.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The policy does not grant `mail.message.body.read`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"No such email in this workspace (or it was deleted).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Download the raw RFC 5322 message (.eml)","tags":["received"],"x-pc-sdk":{"resource":"received","method":"raw","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/received/{id}/attachments/{position}":{"get":{"description":"By its `position` from the detail's attachment manifest. Unscanned, untrusted bytes from a third party. Gated by `mail.message.body.read`.","operationId":"ReceivedController_getAttachment","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","description":"Received email id.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"position","required":true,"in":"path","description":"Attachment position (0-based).","schema":{"type":"number"},"example":0}],"responses":{"200":{"description":"Binary stream. `Content-Type` is the stored attachment media type; `Content-Disposition: attachment`.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`id` is not a uuid or `position` is not an integer.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The policy does not grant `mail.message.body.read`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"No such email in this workspace, or no attachment at that position.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Download one attachment of a received email","tags":["received"],"x-pc-sdk":{"resource":"received.attachments","method":"retrieve","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/received/{id}/read":{"post":{"operationId":"ReceivedController_markRead","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","description":"Received email id.","schema":{"format":"uuid","type":"string"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Marked read (idempotent).","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`id` is not a uuid.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The policy does not grant `mail.read` on every mailbox.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"No such email in this workspace (or it was deleted).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Mark a received email as read","tags":["received"],"x-pc-sdk":{"resource":"received","method":"read","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/messages/timeline":{"get":{"description":"Counts INBOUND mail only: messages received by the workspace's mailboxes, in dense day buckets in [since, until). `metric=sent` (default, a historical name) counts received messages, not outbound sends; `metric=bounced` counts MX-time rejections matched to this workspace by envelope-to. For outbound counts and rates use `GET /emails/metrics`.","operationId":"MessageTimelineController_getTimeline","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"granularity","required":true,"in":"query","description":"Bucket size. Only `day` is supported today; the param is here so future hour/week additions don’t break clients.","schema":{"example":"day","enum":["day"],"type":"string"},"example":"day"},{"name":"since","required":true,"in":"query","description":"Inclusive start of the window (ISO-8601). Treated in UTC for bucket alignment.","schema":{"format":"date-time","example":"2026-04-01T00:00:00Z","type":"string"},"example":"2026-04-01T00:00:00Z"},{"name":"until","required":true,"in":"query","description":"Exclusive end of the window (ISO-8601).","schema":{"format":"date-time","example":"2026-05-01T00:00:00Z","type":"string"},"example":"2026-05-01T00:00:00Z"},{"name":"metric","required":false,"in":"query","description":"Which counter to bucket. `sent` (default) reads from received messages; `bounced` reads from MX-time rejections matching this workspace's mailbox addresses.","schema":{"default":"sent","enum":["sent","bounced"],"type":"string"},"example":"sent"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTimelineResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Day-bucketed inbound message volume for a workspace","tags":["messages"],"x-pc-sdk":{"resource":"messages","method":"timeline","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/templates":{"post":{"operationId":"TemplateController_upsert","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertTemplateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure (bad name / payload).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create or update a template, layout, or partial. Idempotent on (workspace_id, name); `kind` cannot change after the first upsert.","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"TemplateController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"tags","required":false,"in":"query","schema":{"type":"string"},"description":"Comma-separated tag list. A template matches when any of its tags appears in the list."},{"name":"kind","required":false,"in":"query","schema":{"type":"string","enum":["template","layout","partial"]},"description":"Restrict to one kind. Unrecognised values are ignored (no kind filter applied), preserving the pre-pagination behaviour.","example":"template"},{"name":"search","required":false,"in":"query","schema":{"type":"string","maxLength":200},"description":"Case-insensitive substring match on the template name."},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplatesResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid cursor or search term.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List templates / layouts / partials in a workspace, name-ascending and cursor-paginated. Filter via ?kind=template|layout|partial (default: all), ?tags=foo,bar (comma-separated), ?search=<substring of the name>.","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/templates/tags":{"get":{"operationId":"TemplateController_listTags","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplateTagsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Distinct tag list across all templates in this workspace (for autocomplete)","tags":["templates"],"x-pc-sdk":{"resource":"templates.tags","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/templates/{name}":{"get":{"operationId":"TemplateController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"name","required":true,"in":"path","schema":{"type":"string"},"description":"Name of the template.","example":"welcome"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Template not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a template, layout, or partial by name.","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"retrieve","bind":["workspace_id"],"paginated":false}},"delete":{"operationId":"TemplateController_delete","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"name","required":true,"in":"path","schema":{"type":"string"},"description":"Name of the template.","example":"welcome"}],"responses":{"204":{"description":"Template deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Template not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete a template, layout, or partial by name.","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/templates/{name}/render":{"post":{"operationId":"TemplateController_render","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"name","required":true,"in":"path","schema":{"type":"string"},"description":"Name of the template.","example":"welcome"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderedMessageDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Template not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Cannot render a layout/partial — only sendable templates.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Render or schema validation failed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Render a saved template against a data payload. Returns subject + html + text without sending.","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"render","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/templates/preview":{"post":{"operationId":"TemplateController_preview","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderedMessageDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"422":{"description":"Render failed (compile or runtime error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Preview an unsaved draft. Renders subject + bodyHtml against the workspace brand tokens + supplied data, with all workspace layouts/partials registered. Used by the editor for live preview.","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"preview","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/templates/lint":{"post":{"operationId":"TemplateController_lint","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LintTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LintResultDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"422":{"description":"Underlying render failed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Lint a draft for deliverability red flags. Same render pipeline as /preview; returns a 0-100 score (higher is better) and a sorted list of findings (errors first). Self-developed heuristic linter, no external classifier — runs in-process.","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"lint","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/templates/{name}/variables":{"get":{"operationId":"TemplateController_variables","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"name","required":true,"in":"path","schema":{"type":"string"},"description":"Name of the template.","example":"welcome"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateVariablesResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Template not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Variables auto-detected from the saved template body + subject (Handlebars expressions, dotted paths preserved, dedup'd in first-occurrence order).","tags":["templates"],"x-pc-sdk":{"resource":"templates.variables","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/templates/{name}/test-send":{"post":{"operationId":"TemplateController_testSend","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"name","required":true,"in":"path","schema":{"type":"string"},"description":"Name of the template.","example":"welcome"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestSendTemplateDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendAcceptedDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"From-address domain is not registered to this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Template not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Cannot test-send a layout/partial, or `IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different body or route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Invalid from address or render failure; or `from_domain_not_verified` (body `code`, `details: { fqdn, reason }`): the domain of the From address is not itself an active sending domain of this workspace — `reason: not_registered` (unknown, registered to another workspace, or only a subdomain such as `mail.example.com` is verified; a verified subdomain does not cover its parent) or `reason: not_verified` (registered, DNS not verified yet). Refused before anything is recorded or queued; or `domain_not_verified_by_provider` (body `code`): the from-domain's DNS records have been broken for over 72 h (`health: failing`), so the email provider no longer sends for it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","from_domain_not_verified","domain_not_verified_by_provider"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 30 test sends this hour in this workspace: `RATE_LIMITED` with `details: { window, limit, retry_after }`. Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the hourly window resets.","schema":{"type":"integer"}},"ratelimit-limit":{"description":"The hourly test-send limit (30).","schema":{"type":"integer"}},"ratelimit-remaining":{"description":"Always 0 on this 429.","schema":{"type":"integer"}},"ratelimit-reset":{"description":"Seconds until the hourly window resets.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send a test rendering of the template to an arbitrary recipient. Bypasses the suppression list and the ordinary send limits (test sends have their own: 30 per hour per workspace); subject is auto-prefixed with [TEST]; missing variables render as [varname] placeholders.","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"testSend","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/templates/{name}/send":{"post":{"operationId":"TemplateController_send","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"name","required":true,"in":"path","schema":{"type":"string"},"description":"Name of the template.","example":"welcome"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTemplateDto"}}}},"responses":{"202":{"description":"Send accepted; queued for delivery.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendAcceptedDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure (malformed body or recipient).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Template not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"IDEMPOTENCY_KEY_REUSE — same key, different body. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Recipient suppressed (`RECIPIENT_SUPPRESSED`; with a `topic_id`, or a template rendering `{{{unsubscribe_url}}}`, also when the recipient unsubscribed or never opted in: `details.reason` is `unsubscribe` or `no_consent`), `TOPIC_NOT_FOUND`, render failure, or invalid from address; or `from_domain_not_verified` (body `code`, `details: { fqdn, reason }`): the domain of the From address is not itself an active sending domain of this workspace — `reason: not_registered` (unknown, registered to another workspace, or only a subdomain such as `mail.example.com` is verified; a verified subdomain does not cover its parent) or `reason: not_verified` (registered, DNS not verified yet). Refused before anything is recorded or queued; or `domain_not_verified_by_provider` (body `code`): the from-domain's DNS records have been broken for over 72 h (`health: failing`), so the email provider no longer sends for it; or `no_default_sender` (body `code`): the body has no `from` and the workspace has no default sender set (nothing is queued; an `email.skipped` webhook event is logged).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","RECIPIENT_SUPPRESSED","TOPIC_NOT_FOUND","from_domain_not_verified","domain_not_verified_by_provider","no_default_sender"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Over a workspace send limit (60 per minute, 600 per hour, 10,000 per day): `RATE_LIMITED` with `details: { window, limit, retry_after }`. Nothing is recorded or queued. Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the tripped window resets.","schema":{"type":"integer"}},"ratelimit-limit":{"description":"The limit of the window that tripped.","schema":{"type":"integer"}},"ratelimit-remaining":{"description":"Always 0 on this 429.","schema":{"type":"integer"}},"ratelimit-reset":{"description":"Seconds until the tripped window resets.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send a template-rendered message. Pass an `Idempotency-Key` header (1..256 chars, [A-Za-z0-9_\\-:]) to make retries safe — replays return the original response with `Idempotent-Replay: true` for 24h. Same key + different request body returns 409 IDEMPOTENCY_KEY_REUSE.","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"send","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/templates/{name}/send-batch":{"post":{"description":"Two ways to make retries safe. An `Idempotency-Key` header covers the whole request: a retry with the same key and body within 24 h returns the first response (with `Idempotent-Replay: true`) and sends nothing. A per-row `idempotency_key` covers one message: a later batch, or a `/send`, that repeats a row key replays that row instead of sending it again. Both share one dedupe namespace, so the header key must differ from every row key (400 otherwise).","operationId":"TemplateController_sendBatch","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"name","required":true,"in":"path","schema":{"type":"string"},"description":"Name of the template.","example":"welcome"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendBatchDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendBatchOpenApiResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure (malformed body, batch too large), or the `Idempotency-Key` header equals a row `idempotency_key` (`IDEMPOTENCY_KEY_CONFLICTS_WITH_ROW`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","IDEMPOTENCY_KEY_CONFLICTS_WITH_ROW"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Template not found in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"For any row: `from_domain_not_verified` (body `code`, `details: { fqdn, reason }`): the domain of the From address is not itself an active sending domain of this workspace — `reason: not_registered` (unknown, registered to another workspace, or only a subdomain such as `mail.example.com` is verified; a verified subdomain does not cover its parent) or `reason: not_verified` (registered, DNS not verified yet). Refused before anything is recorded or queued (the whole batch is refused); or `domain_not_verified_by_provider` (body `code`): the from-domain's DNS records have been broken for over 72 h (`health: failing`), so the email provider no longer sends for it. The whole batch is refused; no row is sent.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","from_domain_not_verified","domain_not_verified_by_provider"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"The workspace send limits (60 per minute, 600 per hour, 10,000 per day) never 429 a batch: a row over one is rejected in the 200 body with `RATE_LIMITED`, and the other rows are unaffected. Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send up to 100 messages with the same template in one request. Per-row partial-success: each row carries its own status (`accepted` | `rejected`).","tags":["templates"],"x-pc-sdk":{"resource":"templates","method":"sendBatch","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/domains/{domain_id}/test-send":{"post":{"description":"Sends a fixed message (subject `[TEST] Sending from <domain> works`, a short body naming the domain and the From address) so a freshly verified domain can be tried before any template exists. The From address defaults to `test@<domain>` and must be at this exact domain. Like a template test send it skips the suppression list and the ordinary send limits, counts against the workspace test-send limit (30 per hour), and is recorded with `source: test_send`.","operationId":"DomainTestSendController_testSend","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"domain_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the domain.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainTestSendDto"}}}},"responses":{"202":{"description":"Accepted; queued for delivery.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendAcceptedDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"`domain_id` is not a UUID, or the body is malformed (bad `to` or `from`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"`DOMAIN_NOT_FOUND`: no such domain in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","DOMAIN_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different body or route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"`FROM_DOMAIN_MISMATCH`: the From address is not at this domain; or `from_domain_not_verified` (body `code`, `details: { fqdn, reason }`): the domain is receive-only (`reason: not_registered`) or not verified yet (`reason: not_verified`); or `domain_not_verified_by_provider`: its DNS records have been broken for over 72 h (`health: failing`). Refused before anything is recorded or queued.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","FROM_DOMAIN_MISMATCH","from_domain_not_verified","domain_not_verified_by_provider"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 30 test sends this hour in this workspace: `RATE_LIMITED` with `details: { window, limit, retry_after }`. Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the hourly window resets.","schema":{"type":"integer"}},"ratelimit-limit":{"description":"The hourly test-send limit (30).","schema":{"type":"integer"}},"ratelimit-remaining":{"description":"Always 0 on this 429.","schema":{"type":"integer"}},"ratelimit-reset":{"description":"Seconds until the hourly window resets.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send a built-in test email from this domain, no template needed.","tags":["domains"],"x-pc-sdk":{"resource":"domains","method":"testSend","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/contacts/imports":{"post":{"description":"Queues the file and returns the import (`status: queued`); poll `GET .../contacts/imports/{id}` for progress. At most 10 MB and 100,000 rows, two imports running per workspace. Rows that assert consent (`consent` true or a `consented_at` date) are recorded with it and opted in to `topic_ids`; every other row starts without consent. An import emits no per-contact webhook events.","operationId":"ContactImportsController_create","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactImportDto"}}}},"responses":{"202":{"description":"Queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactImportDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"A `topic_ids` entry is not a topic of this workspace (`TOPIC_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","TOPIC_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Two imports are already running (`IMPORT_IN_PROGRESS`), or `IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different body or route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IMPORT_IN_PROGRESS","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"413":{"description":"The CSV is larger than 10 MB (`IMPORT_TOO_LARGE`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["PAYLOAD_TOO_LARGE","IMPORT_TOO_LARGE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Empty file, or no header line with an `email` column (`INVALID_CSV`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","INVALID_CSV"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Import contacts from a CSV file","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.imports","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"ContactImportsController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListContactImportsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List contact imports, newest first","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.imports","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/contacts/imports/{import_id}":{"get":{"operationId":"ContactImportsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"import_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the import.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactImportDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such import in this workspace (`IMPORT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","IMPORT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a contact import and its progress","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.imports","method":"retrieve","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/contacts":{"post":{"description":"Emits `contact.created`. Without `consent`, the contact receives only topics it is explicitly opted in to.","operationId":"ContactsController_create","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"A `topics[].id` is not a topic of this workspace (`TOPIC_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","TOPIC_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"A contact with this email exists (`CONTACT_EXISTS`), the workspace has 100,000 contacts (`CONTACT_LIMIT`), or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","CONTACT_EXISTS","CONTACT_LIMIT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"A `properties` key is not a defined property (`UNKNOWN_CONTACT_PROPERTY`) or its value has the wrong type (`INVALID_CONTACT_PROPERTY_VALUE`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","UNKNOWN_CONTACT_PROPERTY","INVALID_CONTACT_PROPERTY_VALUE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create a contact","tags":["contacts"],"x-pc-sdk":{"resource":"contacts","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"ContactsController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"},{"name":"search","required":false,"in":"query","schema":{"type":"string","maxLength":200},"description":"Case-insensitive substring match on the email address."},{"name":"unsubscribed","required":false,"in":"query","schema":{"type":"boolean"},"description":"Only contacts that are (`true`) or are not (`false`) globally unsubscribed.","example":true}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListContactsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List contacts, newest first","tags":["contacts"],"x-pc-sdk":{"resource":"contacts","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/contacts/{contact}":{"get":{"operationId":"ContactsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"contact","required":true,"in":"path","description":"The contact id, or its email address (URL-encoded).","schema":{"type":"string","example":"ada@example.com"},"example":"ada@example.com"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such contact (`CONTACT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a contact by id or email","tags":["contacts"],"x-pc-sdk":{"resource":"contacts","method":"retrieve","bind":["workspace_id"],"paginated":false}},"patch":{"description":"The email cannot change (delete and re-create). Emits `contact.updated` when something changed.","operationId":"ContactsController_update","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"contact","required":true,"in":"path","description":"The contact id, or its email address (URL-encoded).","schema":{"type":"string","example":"ada@example.com"},"example":"ada@example.com"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContactDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such contact (`CONTACT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"`UNKNOWN_CONTACT_PROPERTY` or `INVALID_CONTACT_PROPERTY_VALUE`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","UNKNOWN_CONTACT_PROPERTY","INVALID_CONTACT_PROPERTY_VALUE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Update a contact","tags":["contacts"],"x-pc-sdk":{"resource":"contacts","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"description":"Removes the contact, its properties and its topic choices. Emits `contact.deleted`. To stop mailing someone, unsubscribe them instead: a deleted contact that later receives a topic send is refused (`no_consent`), but its opt-out is forgotten.","operationId":"ContactsController_remove","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"contact","required":true,"in":"path","description":"The contact id, or its email address (URL-encoded).","schema":{"type":"string","example":"ada@example.com"},"example":"ada@example.com"}],"responses":{"204":{"description":"Deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such contact (`CONTACT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete a contact","tags":["contacts"],"x-pc-sdk":{"resource":"contacts","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/contacts/{contact}/topics":{"get":{"description":"Every topic of the workspace, with the contact's own choice and whether a topic send would reach it now (and why).","operationId":"ContactsController_topics","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"contact","required":true,"in":"path","description":"The contact id, or its email address (URL-encoded).","schema":{"type":"string","example":"ada@example.com"},"example":"ada@example.com"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactTopicsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such contact (`CONTACT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List a contact's topic subscriptions","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.topics","method":"list","bind":["workspace_id"],"paginated":false}},"patch":{"description":"Records the contact's choice per topic (an explicit `opt_in` is consent for that topic). A global unsubscribe still wins: clear it with `PATCH .../contacts/{contact}` `unsubscribed: false`. Emits `contact.updated`.","operationId":"ContactsController_updateTopics","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"contact","required":true,"in":"path","description":"The contact id, or its email address (URL-encoded).","schema":{"type":"string","example":"ada@example.com"},"example":"ada@example.com"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContactTopicsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactTopicsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such contact (`CONTACT_NOT_FOUND`) or topic (`TOPIC_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_NOT_FOUND","TOPIC_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Opt a contact in to or out of topics","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.topics","method":"update","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/contacts/{contact}/segments":{"get":{"description":"Static segments it was added to and rule segments it matches now.","operationId":"ContactSegmentsController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"contact","required":true,"in":"path","description":"The contact id, or its email address (URL-encoded).","schema":{"type":"string","example":"ada@example.com"},"example":"ada@example.com"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactSegmentsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such contact (`CONTACT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List a contact's segments","tags":["segments"],"x-pc-sdk":{"resource":"contacts.segments","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/contacts/{contact}/segments/{segment_id}":{"post":{"description":"Adds the contact. Adding a contact that is already a member changes nothing and answers the same way, with `added_at` from the first time.","operationId":"ContactSegmentsController_add","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"contact","required":true,"in":"path","description":"The contact id, or its email address (URL-encoded).","schema":{"type":"string","example":"ada@example.com"},"example":"ada@example.com"},{"name":"segment_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the segment.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The contact is a member (added now, or already).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentMembershipDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such contact (`CONTACT_NOT_FOUND`) or segment (`SEGMENT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_NOT_FOUND","SEGMENT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"The segment is rule-based: its members follow the rule (`SEGMENT_RULE_BASED`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","SEGMENT_RULE_BASED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Add a contact to a static segment","tags":["segments"],"x-pc-sdk":{"resource":"contacts.segments","method":"add","bind":["workspace_id"],"paginated":false}},"delete":{"description":"204 whether or not it was a member.","operationId":"ContactSegmentsController_remove","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"contact","required":true,"in":"path","description":"The contact id, or its email address (URL-encoded).","schema":{"type":"string","example":"ada@example.com"},"example":"ada@example.com"},{"name":"segment_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the segment.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Not a member (any more).","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such contact (`CONTACT_NOT_FOUND`) or segment (`SEGMENT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_NOT_FOUND","SEGMENT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"The segment is rule-based (`SEGMENT_RULE_BASED`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","SEGMENT_RULE_BASED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Remove a contact from a static segment","tags":["segments"],"x-pc-sdk":{"resource":"contacts.segments","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/contact-properties":{"post":{"description":"At most 50 per workspace.","operationId":"ContactPropertiesController_create","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactPropertyDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactPropertyDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"The key exists (`CONTACT_PROPERTY_EXISTS`), the workspace has 50 properties (`CONTACT_PROPERTY_LIMIT`), or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","CONTACT_PROPERTY_EXISTS","CONTACT_PROPERTY_LIMIT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"The key is a contact field (`RESERVED_PROPERTY_KEY`) or the fallback does not match the type (`INVALID_CONTACT_PROPERTY_VALUE`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","RESERVED_PROPERTY_KEY","INVALID_CONTACT_PROPERTY_VALUE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Define a contact property","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.properties","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"ContactPropertiesController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListContactPropertiesResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List contact properties, newest first","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.properties","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/contact-properties/{property_id}":{"get":{"operationId":"ContactPropertiesController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"property_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the property.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactPropertyDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such property (`CONTACT_PROPERTY_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_PROPERTY_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a contact property","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.properties","method":"retrieve","bind":["workspace_id"],"paginated":false}},"patch":{"description":"The key and type are fixed once created.","operationId":"ContactPropertiesController_update","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"property_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the property.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContactPropertyDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactPropertyDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such property (`CONTACT_PROPERTY_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_PROPERTY_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"The fallback does not match the type (`INVALID_CONTACT_PROPERTY_VALUE`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","INVALID_CONTACT_PROPERTY_VALUE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Change a contact property's fallback value","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.properties","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"description":"Values already stored on contacts stay, but are no longer validated; define the key again to use it.","operationId":"ContactPropertiesController_remove","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"property_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the property.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such property (`CONTACT_PROPERTY_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","CONTACT_PROPERTY_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete a contact property","tags":["contacts"],"x-pc-sdk":{"resource":"contacts.properties","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/topics":{"post":{"description":"Send on a topic with `topic_id` on a template send. Recipients manage their topics on the hosted unsubscribe page. At most 50 topics per workspace.","operationId":"TopicsController_create","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTopicDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"A topic with this name exists (`TOPIC_EXISTS`), the workspace has 50 topics (`TOPIC_LIMIT`), or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","TOPIC_EXISTS","TOPIC_LIMIT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create a topic","tags":["topics"],"x-pc-sdk":{"resource":"topics","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"TopicsController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTopicsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List topics, newest first","tags":["topics"],"x-pc-sdk":{"resource":"topics","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/topics/{topic_id}":{"get":{"operationId":"TopicsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"topic_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the topic.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such topic (`TOPIC_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","TOPIC_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a topic","tags":["topics"],"x-pc-sdk":{"resource":"topics","method":"retrieve","bind":["workspace_id"],"paginated":false}},"patch":{"description":"`default_subscription` cannot change: flipping it would silently subscribe or unsubscribe everyone who never chose.","operationId":"TopicsController_update","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"topic_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the topic.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTopicDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such topic (`TOPIC_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","TOPIC_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Another topic has this name (`TOPIC_EXISTS`), or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","TOPIC_EXISTS","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Update a topic","tags":["topics"],"x-pc-sdk":{"resource":"topics","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"description":"Also deletes every contact's choice for it. Sends naming it are refused afterwards (`TOPIC_NOT_FOUND`).","operationId":"TopicsController_remove","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"topic_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the topic.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such topic (`TOPIC_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","TOPIC_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete a topic","tags":["topics"],"x-pc-sdk":{"resource":"topics","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/segments":{"post":{"description":"Without `rule`, a static segment: add and remove contacts one at a time. With `rule`, a rule segment: its members are the contacts whose fields and properties match, evaluated every time it is read. At most 100 segments per workspace.","operationId":"SegmentsController_create","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSegmentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"A segment with this name exists (`SEGMENT_EXISTS`), the workspace has 100 segments (`SEGMENT_LIMIT`), or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","SEGMENT_EXISTS","SEGMENT_LIMIT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"The rule is invalid (`INVALID_SEGMENT_RULE`; `details.problems` lists each one with its condition index): an unknown field, `contains` on a number property, a missing or mistyped `value`, a `value` on `exists`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","INVALID_SEGMENT_RULE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create a segment","tags":["segments"],"x-pc-sdk":{"resource":"segments","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"SegmentsController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSegmentsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List segments, newest first","tags":["segments"],"x-pc-sdk":{"resource":"segments","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/segments/preview":{"post":{"description":"Counts the contacts a rule selects and returns the newest few, without saving anything.","operationId":"SegmentsController_preview","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewSegmentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentPreviewDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"422":{"description":"The rule is invalid (`INVALID_SEGMENT_RULE`; `details.problems` lists each one with its condition index): an unknown field, `contains` on a number property, a missing or mistyped `value`, a `value` on `exists`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","INVALID_SEGMENT_RULE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Preview a segment rule","tags":["segments"],"x-pc-sdk":{"resource":"segments","method":"preview","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/segments/{segment_id}":{"get":{"operationId":"SegmentsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"segment_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the segment.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such segment (`SEGMENT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","SEGMENT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a segment","tags":["segments"],"x-pc-sdk":{"resource":"segments","method":"retrieve","bind":["workspace_id"],"paginated":false}},"patch":{"description":"Rename it, or change a rule segment's rule. A segment's type (static or rule) is fixed.","operationId":"SegmentsController_update","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"segment_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the segment.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSegmentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such segment (`SEGMENT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","SEGMENT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Another segment has this name (`SEGMENT_EXISTS`), or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","SEGMENT_EXISTS","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"The rule is invalid (`INVALID_SEGMENT_RULE`; `details.problems` lists each one with its condition index): an unknown field, `contains` on a number property, a missing or mistyped `value`, a `value` on `exists`. Or a rule on a static segment (`SEGMENT_TYPE_FIXED`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","INVALID_SEGMENT_RULE","SEGMENT_TYPE_FIXED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Update a segment","tags":["segments"],"x-pc-sdk":{"resource":"segments","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"description":"Contacts are not touched; a static segment's member list goes with it.","operationId":"SegmentsController_remove","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"segment_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the segment.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such segment (`SEGMENT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","SEGMENT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete a segment","tags":["segments"],"x-pc-sdk":{"resource":"segments","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/segments/{segment_id}/contacts":{"get":{"description":"Newest contact first. For a rule segment, the contacts matching its rule right now.","operationId":"SegmentsController_contacts","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"segment_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the segment.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"},{"name":"unsubscribed","required":false,"in":"query","schema":{"type":"boolean"},"description":"Only members that are (`true`) or are not (`false`) globally unsubscribed.","example":true}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSegmentContactsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such segment (`SEGMENT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","SEGMENT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List a segment's contacts","tags":["segments"],"x-pc-sdk":{"resource":"segments.contacts","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/segments/{segment_id}/metrics":{"get":{"description":"Counted on request.","operationId":"SegmentsController_metrics","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"segment_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the segment.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentMetricsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such segment (`SEGMENT_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","SEGMENT_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"A segment's size and unsubscribed share","tags":["segments"],"x-pc-sdk":{"resource":"segments","method":"metrics","bind":["workspace_id"],"paginated":false}}},"/v1/u/{token}":{"get":{"description":"What `{{{unsubscribe_url}}}` and the `List-Unsubscribe` header open: an HTML page in the workspace brand with an Unsubscribe button for the topic the email was sent on (or for everything), and the public topics as checkboxes. Opening it changes nothing. An unknown link answers 404 and an expired one (links last 365 days) 410, both as a page.","operationId":"UnsubscribeController_page","parameters":[{"name":"token","required":true,"in":"path","description":"The token from the unsubscribe link (`u1.` followed by base64url).","schema":{"type":"string","pattern":"^u1\\.[A-Za-z0-9_-]{40,600}$"}}],"responses":{"200":{"description":"The preferences page.","content":{"text/html":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"404":{"description":"Unknown or malformed link (HTML page).","content":{"text/html":{"schema":{"type":"string"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"410":{"description":"Expired link (HTML page).","content":{"text/html":{"schema":{"type":"string"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["GONE"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[],"summary":"Hosted unsubscribe and preferences page (no authentication).","tags":["public"],"x-pc-sdk":false},"post":{"description":"The `List-Unsubscribe-Post: List-Unsubscribe=One-Click` target. A mailbox provider POSTs `List-Unsubscribe=One-Click` (form-encoded); the recipient is unsubscribed from the topic the email was sent on, or from all unsubscribable mail when it had no topic, and the answer is a short `200 text/plain`. No confirmation step, as RFC 8058 requires. The hosted page posts `action=unsubscribe` (same effect) or `action=save` with `topic` (repeated, the topic ids to stay subscribed to; unchecked public topics are opted out) and `all=1` (unsubscribe from everything), and gets the page back. Transactional mail (a send with no topic whose template has no unsubscribe link) is never affected. Emits `contact.updated`, and `contact.created` for a recipient who was not a contact yet.","operationId":"UnsubscribeController_submit","parameters":[{"name":"token","required":true,"in":"path","description":"The token from the unsubscribe link (`u1.` followed by base64url).","schema":{"type":"string","pattern":"^u1\\.[A-Za-z0-9_-]{40,600}$"}}],"requestBody":{"required":false,"description":"Form-encoded. A mailbox provider sends exactly `List-Unsubscribe=One-Click` (RFC 8058; any body without `action` is treated the same, multipart included). The hosted page sends `action`, `topic` and `all`.","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["unsubscribe","save"]},"topic":{"oneOf":[{"type":"string","format":"uuid"},{"type":"array","items":{"type":"string","format":"uuid"}}]},"all":{"type":"string","enum":["1"]}}}}}},"responses":{"200":{"description":"Unsubscribed (`text/plain` for one-click) or the updated page (`text/html`).","content":{"text/plain":{"schema":{"type":"string"}},"text/html":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"404":{"description":"Unknown or malformed link (`text/plain`, or a page for the hosted form).","content":{"text/plain":{"schema":{"type":"string"}},"text/html":{"schema":{"type":"string"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"410":{"description":"Expired link (`text/plain`, or a page for the hosted form).","content":{"text/plain":{"schema":{"type":"string"}},"text/html":{"schema":{"type":"string"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["GONE"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[],"summary":"One-click unsubscribe (RFC 8058) and the preferences form (no authentication).","tags":["public"],"x-pc-sdk":false}},"/v1/workspaces/{workspace_id}/sending-defaults":{"get":{"description":"The From used by template sends that name none, with the live verification status of its domain. `default_sender` is null when none is set.","operationId":"SendingDefaultsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendingDefaultsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get the workspace default sender","tags":["sending-defaults"],"x-pc-sdk":{"resource":"sendingDefaults","method":"retrieve","bind":["workspace_id"],"paginated":false}},"put":{"description":"Replaces the default sender (`address: null` clears it). The change applies to the next send of every product at once, and emits a `sending_defaults.updated` webhook event. Repeating the same request changes nothing, so it takes no `Idempotency-Key`.","operationId":"SendingDefaultsController_put","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutSendingDefaultsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendingDefaultsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"422":{"description":"`sender_domain_not_in_workspace` (`details: { fqdn }`): the address is not on a sending domain of this workspace (unknown, another workspace's, or receive-only). `INVALID_FROM_ADDRESS`: the address could not be parsed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","sender_domain_not_in_workspace","INVALID_FROM_ADDRESS"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Set or clear the workspace default sender","tags":["sending-defaults"],"x-pc-sdk":{"resource":"sendingDefaults","method":"update","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/emails":{"post":{"description":"Send your own `html` and/or `text`, or a saved `template`, to up to 50 recipients across `to`, `cc` and `bcc`, with `reply_to`, custom `headers` and `tags`. Every recipient gets its own copy (its own message in `GET /messages`, suppression check and delivery status) showing the same `To` and `Cc` headers; `bcc` recipients appear in no header. A recipient on the suppression list (or unsubscribed, for a template with an unsubscribe link) is left out with a `suppressed` message, and the email is still accepted. Counts one send per recipient against the workspace limits. Pass an `Idempotency-Key` header to make retries safe.","operationId":"EmailsController_send","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailDto"}}}},"responses":{"202":{"description":"Accepted; queued for delivery.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure; `EMAIL_CONTENT_CONFLICT` (both or neither of `html`/`text` and `template`); `RECIPIENT_LIMIT` (more than 50 recipients); `MAIL_HEADER_NOT_ALLOWED` (`details.headers` names the refused headers).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","EMAIL_CONTENT_CONFLICT","RECIPIENT_LIMIT","MAIL_HEADER_NOT_ALLOWED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"`TEMPLATE_NOT_FOUND`: the `template.name` is not a template of this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","TEMPLATE_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"`from_domain_not_verified` (body `code`, `details: { fqdn, reason }`): the domain of the From address is not itself an active sending domain of this workspace (`reason: not_registered` or `not_verified`); refused before anything is recorded or queued. Or `domain_not_verified_by_provider`: the from-domain's DNS records have been broken for over 72 h, so the email provider no longer sends for it. Or `INVALID_FROM_ADDRESS`. Or `TEMPLATE_RENDER_FAILED` / `TEMPLATE_DATA_INVALID` for a template send.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","from_domain_not_verified","domain_not_verified_by_provider","INVALID_FROM_ADDRESS","TEMPLATE_RENDER_FAILED","TEMPLATE_DATA_INVALID"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Over a workspace send limit (60 per minute, 600 per hour, 10,000 per day; each recipient counts): `RATE_LIMITED` with `details: { window, limit, retry_after }`. Nothing is recorded or queued. Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the tripped window resets.","schema":{"type":"integer"}},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send an email","tags":["emails"],"x-pc-sdk":{"resource":"emails","method":"send","bind":["workspace_id"],"paginated":false}},"get":{"description":"One entry per email (send call), newest first, with its recipients and `last_event`, the worst status across its messages. Filter by tags with `tag[name]=value` (repeat for several; all must match). Emails sent before 2026-11-06 appear as one-recipient emails.","operationId":"EmailsController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"},{"name":"tag","required":false,"in":"query","style":"deepObject","explode":true,"schema":{"type":"object","additionalProperties":{"type":"string"}},"description":"Tag filter: `tag[category]=confirm_email`. Up to 10 pairs; an email matches when it carries every one."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListEmailsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Invalid cursor or tag filter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List emails","tags":["emails"],"x-pc-sdk":{"resource":"emails","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/emails/batch":{"post":{"description":"Each row is a `POST /emails` body plus an optional `idempotency_key`, processed independently: the response reports `accepted` (with the email `id`) or `rejected` (with `error.code`) per row. An `Idempotency-Key` header covers the whole request; a row `idempotency_key` covers one row, in the same dedupe namespace (so the header must differ from every row key).","operationId":"EmailsController_sendBatch","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailBatchDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendBatchOpenApiResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"Validation failure (malformed row, more than 100 rows), or `IDEMPOTENCY_KEY_CONFLICTS_WITH_ROW`: the `Idempotency-Key` header equals a row `idempotency_key`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR","IDEMPOTENCY_KEY_CONFLICTS_WITH_ROW"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"For any row: `from_domain_not_verified` (body `code`, `details: { fqdn, reason }`): the domain of the From address is not itself an active sending domain of this workspace (`reason: not_registered` or `not_verified`); refused before anything is recorded or queued. Or `domain_not_verified_by_provider`: the from-domain's DNS records have been broken for over 72 h, so the email provider no longer sends for it. Or `INVALID_FROM_ADDRESS`. The whole batch is refused; no row is sent.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","from_domain_not_verified","domain_not_verified_by_provider","INVALID_FROM_ADDRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"The workspace send limits never 429 a batch: a row over one is rejected in the 200 body with `RATE_LIMITED`, and the other rows are unaffected. Per-IP limit: more than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send up to 100 emails in one request","tags":["emails"],"x-pc-sdk":{"resource":"emails","method":"batch","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/emails/{id}":{"get":{"description":"The email as sent (from, to, cc, bcc, reply_to, subject, tags, custom headers) with one entry per recipient message and `last_event`, the worst status across them. Bodies are on `GET /messages/{id}/body`.","operationId":"EmailsController_retrieve","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the email.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDetailDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"`EMAIL_NOT_FOUND`: no email with this id in this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","EMAIL_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Retrieve an email","tags":["emails"],"x-pc-sdk":{"resource":"emails","method":"retrieve","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/broadcasts":{"post":{"description":"Content is a saved template (`template_name`) or inline Handlebars (`html`, `subject`, optional `text`). The audience is a segment, a topic, or both. Nothing is sent until `POST .../send`.","operationId":"BroadcastsController_create","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBroadcastDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BroadcastDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"`segment_id` or `topic_id` does not name one of this workspace's (`SEGMENT_NOT_FOUND` / `TOPIC_NOT_FOUND`), or both `template_name` and `html` were given (`BROADCAST_CONTENT_CONFLICT`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","SEGMENT_NOT_FOUND","TOPIC_NOT_FOUND","BROADCAST_CONTENT_CONFLICT"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Create a broadcast (draft)","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts","method":"create","bind":["workspace_id"],"paginated":false}},"get":{"operationId":"BroadcastsController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"},{"name":"status","required":false,"in":"query","description":"Only broadcasts in this status.","schema":{"enum":["draft","scheduled","sending","sent","canceled"],"type":"string"},"example":"draft"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBroadcastsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List broadcasts, newest first","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/broadcasts/audience":{"get":{"description":"How many contacts a broadcast to this segment and/or topic would reach if it were sent now: members of the segment, subscribed to the topic, minus anyone unsubscribed or on the suppression list.","operationId":"BroadcastsController_audience","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"segment_id","required":false,"in":"query","description":"Count the contacts in this segment; omit for every subscribed contact.","schema":{"type":"string","format":"uuid"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"topic_id","required":false,"in":"query","description":"Leave out contacts who opted out of this topic.","schema":{"type":"string","format":"uuid"},"example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BroadcastAudienceDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"422":{"description":"Neither given (`AUDIENCE_REQUIRED`), or one does not exist in this workspace (`SEGMENT_NOT_FOUND` / `TOPIC_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","AUDIENCE_REQUIRED","SEGMENT_NOT_FOUND","TOPIC_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Count a broadcast audience","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts","method":"audience","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/broadcasts/{broadcast_id}":{"get":{"description":"Includes `counts` once sending has started: recipients, sent, delivered, bounced, complained, opened, clicked, unsubscribed.","operationId":"BroadcastsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"broadcast_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the broadcast.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BroadcastDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such broadcast (`BROADCAST_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","BROADCAST_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a broadcast","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts","method":"retrieve","bind":["workspace_id"],"paginated":false}},"patch":{"description":"Only drafts can change; null clears an optional field.","operationId":"BroadcastsController_update","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"broadcast_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the broadcast.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBroadcastDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BroadcastDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such broadcast (`BROADCAST_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","BROADCAST_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Not a draft any more (`BROADCAST_NOT_DRAFT`, `details.status`), or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","BROADCAST_NOT_DRAFT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"`segment_id` or `topic_id` does not name one of this workspace's (`SEGMENT_NOT_FOUND` / `TOPIC_NOT_FOUND`), or both `template_name` and `html` were given (`BROADCAST_CONTENT_CONFLICT`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","SEGMENT_NOT_FOUND","TOPIC_NOT_FOUND","BROADCAST_CONTENT_CONFLICT"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Update a draft broadcast","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts","method":"update","bind":["workspace_id"],"paginated":false}},"delete":{"description":"Drafts, sent and canceled broadcasts, with their recipient list. The messages themselves stay in the message log.","operationId":"BroadcastsController_remove","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"broadcast_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the broadcast.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"204":{"description":"Deleted.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such broadcast (`BROADCAST_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","BROADCAST_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Scheduled or sending: cancel it first (`BROADCAST_NOT_DELETABLE`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","BROADCAST_NOT_DELETABLE"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Delete a broadcast","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/broadcasts/{broadcast_id}/send":{"post":{"description":"Now, or at `scheduled_at`. When sending starts the audience is frozen (segment ∩ topic subscribers − unsubscribed − suppression list) and the messages go out at the broadcast rate (default 120 per minute; separate from the transactional limit), on the marketing stream, each with a one-click unsubscribe link and `List-Unsubscribe` headers. The send survives restarts: it continues from the recipients not yet sent.","operationId":"BroadcastsController_send","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"broadcast_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the broadcast.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendBroadcastDto"}}}},"responses":{"202":{"description":"`status` is `sending` or `scheduled`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BroadcastDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such broadcast (`BROADCAST_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","BROADCAST_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Not a draft (`BROADCAST_NOT_DRAFT`), or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","BROADCAST_NOT_DRAFT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Not ready: `UNSUBSCRIBE_LINK_REQUIRED` (the body does not contain `{{{unsubscribe_url}}}`) or `BROADCAST_NOT_READY` (`details.problems`: no audience, no content, no subject, missing template, no From); `BROADCAST_AUDIENCE_EMPTY` (nobody to send to); `INVALID_FROM_ADDRESS`; or `from_domain_not_verified` (`details: { fqdn, reason }`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNPROCESSABLE_ENTITY","UNSUBSCRIBE_LINK_REQUIRED","BROADCAST_NOT_READY","BROADCAST_AUDIENCE_EMPTY","INVALID_FROM_ADDRESS","from_domain_not_verified"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send or schedule a broadcast","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts","method":"send","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/broadcasts/{broadcast_id}/cancel":{"post":{"description":"Recipients not sent yet are marked `canceled`; messages already handed off are not recalled.","operationId":"BroadcastsController_cancel","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"broadcast_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the broadcast.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BroadcastDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such broadcast (`BROADCAST_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","BROADCAST_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Draft, sent or already canceled (`BROADCAST_NOT_CANCELABLE`), or `IDEMPOTENCY_KEY_REUSE`. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","BROADCAST_NOT_CANCELABLE","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Cancel a scheduled or sending broadcast","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts","method":"cancel","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/broadcasts/{broadcast_id}/duplicate":{"post":{"description":"A new draft with the same content and audience.","operationId":"BroadcastsController_duplicate","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"broadcast_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the broadcast.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BroadcastDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such broadcast (`BROADCAST_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","BROADCAST_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Duplicate a broadcast","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts","method":"duplicate","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/broadcasts/{broadcast_id}/recipients":{"get":{"description":"In send order, with each message status.","operationId":"BroadcastsController_recipients","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"broadcast_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the broadcast.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Page size. Defaults to 20; values above 100 are clamped to 100.","example":20},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `pagination.next_cursor`. Omit for the first page.","example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0xMS0wMVQwMDowMDowMFoifQ"},{"name":"status","required":false,"in":"query","description":"Only recipients in this status.","schema":{"enum":["pending","sending","sent","skipped","failed","canceled"],"type":"string"},"example":"pending"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBroadcastRecipientsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such broadcast (`BROADCAST_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","BROADCAST_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List a broadcast's recipients","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts.recipients","method":"list","bind":["workspace_id"],"paginated":true}}},"/v1/workspaces/{workspace_id}/broadcasts/{broadcast_id}/clicked-links":{"get":{"description":"Most clicked first. Empty until click tracking is enabled.","operationId":"BroadcastsController_clickedLinks","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"broadcast_id","required":true,"in":"path","schema":{"type":"string","format":"uuid"},"description":"Id of the broadcast.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClickedLinksResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No such broadcast (`BROADCAST_NOT_FOUND`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND","BROADCAST_NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Links clicked in a broadcast","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts.clickedLinks","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/broadcast-settings":{"get":{"description":"The messages-per-minute pace broadcasts go out at.","operationId":"BroadcastSettingsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BroadcastSettingsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get the broadcast settings","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts.settings","method":"retrieve","bind":["workspace_id"],"paginated":false}},"put":{"description":"Set the workspace campaign pace (1 to 300 messages per minute; null for the default, 120). It never affects transactional sends, which have their own limit.","operationId":"BroadcastSettingsController_update","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBroadcastSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BroadcastSettingsDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Update the broadcast settings","tags":["broadcasts"],"x-pc-sdk":{"resource":"broadcasts.settings","method":"update","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/integrations":{"get":{"description":"Returns one entry per connected provider (GitHub, …). No secrets in the response — only public identifiers + status + sync stamps.","operationId":"IntegrationsController_list","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListIntegrationsResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List connected workspace integrations.","tags":["integrations"],"x-pc-sdk":{"resource":"integrations","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/integrations/{provider}":{"get":{"description":"Includes the provider's `credentials_redacted` view. Secret fields (access tokens, signing keys) are never included.","operationId":"IntegrationsController_get","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"provider","required":true,"in":"path","schema":{"type":"string"},"description":"The integration provider (`github`).","example":"github"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationDetailDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"No integration of the requested provider for this workspace.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get a single integration detail with redacted credentials.","tags":["integrations"],"x-pc-sdk":{"resource":"integrations","method":"retrieve","bind":["workspace_id"],"paginated":false}},"delete":{"description":"Hard delete — the encrypted blob is removed. The customer must reconnect via the provider-specific OAuth flow to restore access.","operationId":"IntegrationsController_disconnect","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"provider","required":true,"in":"path","schema":{"type":"string"},"description":"The integration provider (`github`).","example":"github"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Disconnected.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Disconnect an integration. Deletes the credential row.","tags":["integrations"],"x-pc-sdk":{"resource":"integrations","method":"delete","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/integrations/github/repos":{"get":{"operationId":"GitHubController_listRepos","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GitHubRepoDto"}}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List repos visible to the connected GitHub account.","tags":["integrations"],"x-pc-sdk":{"resource":"integrations.github.repos","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/integrations/github/repos/{owner}/{repo}/branches":{"get":{"operationId":"GitHubController_listBranches","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"owner","required":true,"in":"path","schema":{"type":"string"},"description":"Owner (user or organisation) of the GitHub repository.","example":"acme"},{"name":"repo","required":true,"in":"path","schema":{"type":"string"},"description":"Name of the GitHub repository.","example":"email-templates"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GitHubBranchDto"}}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"List branches for the given repo.","tags":["integrations"],"x-pc-sdk":{"resource":"integrations.github.repos.branches","method":"list","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/integrations/github/settings":{"put":{"operationId":"GitHubController_updateSettings","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGitHubSettingsDto"}}}},"responses":{"204":{"description":"Saved.","headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Set the repo + branch + templates path to sync from.","tags":["integrations"],"x-pc-sdk":{"resource":"integrations.github.settings","method":"update","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/integrations/github/sync":{"post":{"operationId":"GitHubController_startSync","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartSyncResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Trigger an immediate sync from GitHub. Returns a sync id to poll.","tags":["integrations"],"x-pc-sdk":{"resource":"integrations.github.sync","method":"create","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/integrations/github/sync/{sync_id}":{"get":{"operationId":"GitHubController_getSyncStatus","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"sync_id","required":true,"in":"path","schema":{"type":"string"},"description":"Id of the sync."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncStatusDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Run not found or expired.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Poll a sync run's status.","tags":["integrations"],"x-pc-sdk":{"resource":"integrations.github.sync","method":"retrieve","bind":["workspace_id"],"paginated":false}}},"/v1/workspaces/{workspace_id}/integrations/github/connect":{"post":{"description":"The frontend redirects the user to `authorize_url`; GitHub bounces back to the `/callback` endpoint with a `code` + `state` pair. state is single-use, 5-minute TTL.","operationId":"GitHubOAuthController_connect","parameters":[{"name":"workspace_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"},"description":"Id of the workspace.","example":"3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"Idempotency-Key","in":"header","description":"Opaque client-generated string (1–256 chars, `[A-Za-z0-9_-:]`) used to deduplicate retries within a 24h window. A retry with the same key and body returns the original response with `Idempotent-Replay: true`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectGitHubRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectGitHubResponseDto"}}},"headers":{"X-RateLimit-Limit-short":{"$ref":"#/components/headers/X-RateLimit-Limit-short"},"X-RateLimit-Remaining-short":{"$ref":"#/components/headers/X-RateLimit-Remaining-short"},"X-RateLimit-Reset-short":{"$ref":"#/components/headers/X-RateLimit-Reset-short"},"X-RateLimit-Limit-long":{"$ref":"#/components/headers/X-RateLimit-Limit-long"},"X-RateLimit-Remaining-long":{"$ref":"#/components/headers/X-RateLimit-Remaining-long"},"X-RateLimit-Reset-long":{"$ref":"#/components/headers/X-RateLimit-Reset-long"},"Idempotent-Replay":{"description":"`true` when this response is a replay of an earlier request with the same `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"description":"A resource id in the path is not a UUID, or the request failed validation (`BAD_REQUEST` / `VALIDATION_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["BAD_REQUEST","VALIDATION_ERROR"]},"401":{"description":"Missing, expired or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["UNAUTHORIZED"]},"403":{"description":"The caller lacks the action this route requires on the resource, or Mail is not enabled for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["FORBIDDEN"]},"404":{"description":"Workspace not found: no workspace has this `workspaceId`, or it is not a UUID (`NOT_FOUND`). A workspace the caller is not a member of answers 403. Routes that read a resource also answer 404 when the resource is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["NOT_FOUND"]},"409":{"description":"`IDEMPOTENCY_KEY_REUSE`: the `Idempotency-Key` was already used with a different request body or on a different route. Idempotency: `IDEMPOTENCY_KEY_REUSE` when this `Idempotency-Key` was already used with a different body or route; `IDEMPOTENCY_IN_PROGRESS` while another request with the same key is still running (retry after `Retry-After` seconds, with the same key).","headers":{"Retry-After":{"description":"Seconds to wait before retrying with the same key (sent with `IDEMPOTENCY_IN_PROGRESS`).","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["CONFLICT","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_IN_PROGRESS"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"More than 20 requests per second or 600 per minute from this client IP (`RATE_LIMITED`); wait `Retry-After` seconds.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Retry-After-short":{"$ref":"#/components/headers/Retry-After-short"},"Retry-After-long":{"$ref":"#/components/headers/Retry-After-long"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"x-pc-error-codes":["RATE_LIMITED"],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Mint a GitHub OAuth state token and return the authorize URL.","tags":["integrations"],"x-pc-sdk":{"resource":"integrations.github","method":"connect","bind":["workspace_id"],"paginated":false}}}},"info":{"title":"Mail API","description":"Transactional and marketing email for the ProductCraft platform: send email and templates, verify sending and receiving domains, manage contacts, topics, segments and broadcasts, read received mail, and get delivery events by webhook.\n\n## Rate limits\n\nEvery `/v1` route is limited per client IP to 20 requests per second and 600 per minute. Each response carries `X-RateLimit-Limit-short`, `X-RateLimit-Remaining-short`, `X-RateLimit-Reset-short` (the one-second window) and the same three with `-long` (the one-minute window). Over either limit the response is `429` with code `RATE_LIMITED` and a `Retry-After` header in seconds.\n\nSending is also limited per workspace: 60 emails per minute, 600 per hour and 10,000 per day (test sends: 30 per hour, counted separately). A send over a workspace limit is `429` `RATE_LIMITED` with `Retry-After`, `ratelimit-limit`, `ratelimit-remaining` and `ratelimit-reset` for the window that tripped, and `details: { window, limit, retry_after }`. In a batch send, a row over the limit is rejected with `RATE_LIMITED` and the other rows are unaffected.\n\nSome routes have their own, tighter limits (domain lookups, DNS checks, exports, share links); each says so in its `429` response.","version":"0.1.0","contact":{}},"tags":[{"name":"brand","description":"The workspace brand used by branded emails, the unsubscribe page and hosted pages."},{"name":"broadcasts","description":"Marketing sends to a segment or topic: drafts, scheduling, sending, recipients and click statistics."},{"name":"contacts","description":"Contacts, their custom properties, imports from CSV, and their topic subscriptions."},{"name":"deliverability","description":"A deliverability verdict per sending domain, from recent bounces, complaints and DNS state."},{"name":"domains","description":"Sending and receiving domains: DNS records and their checks, one-click DNS setup (Domain Connect and provider APIs), share links, lookups and the domain event timeline."},{"name":"emails","description":"Send email: one email to up to 50 recipients (`POST /emails`), a batch of up to 100, and the sent emails with their per-recipient status."},{"name":"integrations","description":"Connected services, today GitHub, which syncs templates from a repository."},{"name":"mailboxes","description":"Mailboxes on a receiving domain and the messages delivered to them."},{"name":"messages","description":"Messages delivered to a mailbox (raw MIME, attachments, read state), and the daily timeline of sent mail."},{"name":"metrics","description":"Delivery metrics over time (sent, delivered, bounced, complained) for the workspace."},{"name":"outbound-messages","description":"The per-recipient delivery log of everything the workspace sent (`messages` in the SDKs): status, events, stored bodies, CSV export, retention settings and the GDPR erase by recipient."},{"name":"outbound-webhooks","description":"Webhook endpoints that receive `email.*`, `domain.*`, `suppression.*`, `contact.*` and `sending_defaults.updated` events, their delivery log and replays. The per-slot legacy routes are deprecated."},{"name":"public","description":"Public pages linked from emails (unsubscribe and preferences) and shared domain setup. No API key: the token in the link is the credential."},{"name":"received","description":"Every email received by the workspace's domains, with raw MIME and attachments."},{"name":"segments","description":"Static and rule-based segments of contacts, used as broadcast audiences."},{"name":"sending-defaults","description":"The workspace default sender, used when a template send gives no `from`."},{"name":"smtp-config","description":"Send through your own SMTP server instead of ProductCraft's: the workspace configuration, per-domain overrides and connection checks."},{"name":"stats","description":"Send totals and a daily series for the workspace dashboard."},{"name":"suppression","description":"Addresses that are never sent to: added by bounces, complaints or by hand."},{"name":"templates","description":"Handlebars templates (with layouts and partials): create, render, lint, test-send, and send to one recipient or a batch."},{"name":"topics","description":"Subscription topics: what a contact can opt in to or out of on the unsubscribe page."}],"servers":[{"url":"https://api.mail.productcraft.co","description":"Mail API"}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}},"schemas":{"ErrorParamDto":{"type":"object","properties":{"param":{"type":"string","description":"Wire path of the invalid field: `email`, `items.0.display_name`.","example":"email"},"message":{"type":"string","description":"What is wrong with it; the same text as the field's entry in an array `message`.","example":"email must be an email"},"code":{"type":"string","description":"The failed rule (class-validator constraint name, e.g. `isEmail`, `isUuid`, `whitelistValidation` for a field the operation does not declare), or `invalid`.","example":"isEmail"}},"required":["param","message","code"]},"ErrorResponseDto":{"type":"object","properties":{"status_code":{"type":"number","description":"HTTP status code, same as the response status.","example":404},"statusCode":{"type":"number","description":"Deprecated alias of `status_code`, same value. Kept so existing clients keep working; read `status_code`. Error responses carry `Deprecation: true` while it is sent.","example":404,"deprecated":true},"message":{"description":"Human-readable error message. A string, or on a `VALIDATION_ERROR` an array with one message per invalid field (the same texts as `errors[].message`). Branch on `code`, not on this.","oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"example":"Domain not found"},"code":{"description":"Stable, machine-readable error code; branch on this, not on `message`. Always present. A route-specific code when the route defines one, otherwise the generic code for the status (`NOT_FOUND`, `VALIDATION_ERROR`, `RATE_LIMITED`, ...). Open set: accept codes you do not know. Each code is documented at https://productcraft.co/docs/errors#<code>.","example":"NOT_FOUND","allOf":[{"$ref":"#/components/schemas/MailErrorCode"}]},"request_id":{"type":"string","description":"The request's id, same as the `X-Request-Id` response header. Quote it when contacting support.","pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$","example":"req_6f1c2a9d4b7e4f0a8c3d2e1f0a9b8c7d"},"errors":{"description":"One entry per invalid request field on a `VALIDATION_ERROR`; empty on every other error.","type":"array","items":{"$ref":"#/components/schemas/ErrorParamDto"}},"details":{"type":"object","description":"Structured context for errors a client has to act on, keyed in snake_case and specific to the code (e.g. `{ fqdn, reason }` on `from_domain_not_verified`). Absent on most errors.","additionalProperties":true,"example":{"fqdn":"mail.example.com","reason":"not_verified"}}},"required":["status_code","message","code","request_id","errors"]},"ResolvedBrandTokensDto":{"type":"object","properties":{"logo_url":{"type":"string","description":"Logo shown at the top of branded emails and pages; null for none.","format":"uri","nullable":true},"brand_name":{"type":"string","description":"Name shown in branded emails and pages; null falls back to the workspace name.","nullable":true},"primary_color":{"type":"string","description":"Primary colour (buttons and links), as a hex value.","example":"#2d29d7"},"secondary_color":{"type":"string","description":"Secondary accent colour, as a hex value.","example":"#4338ca"},"text_color":{"type":"string","description":"Body text colour, as a hex value.","example":"#0a0a0e"},"muted_text_color":{"type":"string","description":"Muted text colour (footers, hints), as a hex value.","example":"#6b7280"},"background_color":{"type":"string","description":"Page background colour, as a hex value.","example":"#f4f4f7"},"card_background_color":{"type":"string","description":"Background colour of the content card, as a hex value.","example":"#ffffff"},"font_stack":{"type":"string","description":"CSS font stack used in branded emails and pages.","example":"Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica Neue, Arial, sans-serif"},"button_radius":{"type":"string","description":"Corner radius of buttons, as a CSS length.","example":"6px"},"container_max_width":{"type":"string","description":"Maximum width of the content card, as a CSS length.","example":"560px"},"footer_html":{"type":"string","description":"HTML footer appended to branded emails; null for none.","nullable":true},"footer_address":{"type":"string","description":"Postal address shown in the footer of marketing mail; null for none.","nullable":true},"social_links":{"type":"object","description":"Map of social-platform → URL.","additionalProperties":{"type":"string"}},"extras":{"type":"object","description":"Extra key/value tokens addressable as {{brand.extras.<key>}} in templates.","additionalProperties":{"type":"string"}}},"required":["logo_url","brand_name","primary_color","secondary_color","text_color","muted_text_color","background_color","card_background_color","font_stack","button_radius","container_max_width","footer_html","footer_address","social_links","extras"],"x-pc-sdk-model":"ResolvedBrandTokens"},"RawBrandDto":{"type":"object","properties":{"logo_url":{"type":"string","description":"Stored logo URL; null when not set.","format":"uri","nullable":true},"brand_name":{"type":"string","description":"Stored brand name; null when not set (the workspace name is used).","nullable":true},"primary_color":{"type":"string","description":"Stored primary colour; null uses the default.","nullable":true},"secondary_color":{"type":"string","description":"Stored secondary colour; null uses the default.","nullable":true},"text_color":{"type":"string","description":"Stored text colour; null uses the default.","nullable":true},"muted_text_color":{"type":"string","description":"Stored muted text colour; null uses the default.","nullable":true},"background_color":{"type":"string","description":"Stored background colour; null uses the default.","nullable":true},"card_background_color":{"type":"string","description":"Stored card background colour; null uses the default.","nullable":true},"font_stack":{"type":"string","description":"Stored font stack; null uses the default.","nullable":true},"button_radius":{"type":"string","description":"Stored button radius; null uses the default.","nullable":true},"container_max_width":{"type":"string","description":"Stored container width; null uses the default.","nullable":true},"footer_html":{"type":"string","description":"Stored footer HTML; null for none.","nullable":true},"footer_address":{"type":"string","description":"Stored footer postal address; null for none.","nullable":true},"social_links":{"type":"object","description":"Social profile links keyed by network, returned exactly as stored; null when not set.","additionalProperties":true,"nullable":true},"extras":{"type":"object","description":"Your own extra brand values, keyed as you sent them; null when not set.","additionalProperties":true,"nullable":true},"updated_at":{"type":"string","description":"When the brand was last changed.","format":"date-time"}},"required":["logo_url","brand_name","primary_color","secondary_color","text_color","muted_text_color","background_color","card_background_color","font_stack","button_radius","container_max_width","footer_html","footer_address","social_links","extras","updated_at"],"x-pc-sdk-model":"RawBrand"},"BrandResponseDto":{"type":"object","properties":{"resolved":{"description":"Fully-resolved tokens every render uses. The frontend reads this for previews so what the editor shows == what recipients get.","allOf":[{"$ref":"#/components/schemas/ResolvedBrandTokensDto"}]},"raw":{"nullable":true,"description":"User-set values only (null when the workspace has never customised). Null fields signal \"not customised — falling through to default\".","allOf":[{"$ref":"#/components/schemas/RawBrandDto"}]}},"required":["resolved","raw"],"x-pc-sdk-model":"Brand"},"UpdateBrandDto":{"type":"object","properties":{"logo_url":{"type":"string","description":"Public URL of your logo. Recommended: PNG/SVG, ≤200px tall, hosted on a domain you control or any CDN reachable at send time.","format":"uri","maxLength":2048},"brand_name":{"type":"string","description":"Display name shown in the email header (falls back to your workspace display name if not set)."},"primary_color":{"type":"string","description":"Primary brand color. Used for buttons, links, and accent strokes. Hex string (e.g. #2d29d7)."},"secondary_color":{"type":"string","description":"Secondary brand color, typically darker than primary. Used for hover states + secondary accents."},"text_color":{"type":"string","description":"Body text color (default: near-black)."},"muted_text_color":{"type":"string","description":"Muted text color for footers + secondary copy."},"background_color":{"type":"string","description":"Page background — the area outside the email card."},"card_background_color":{"type":"string","description":"Email card background."},"font_stack":{"type":"string","description":"CSS font-family stack. Email clients can't use webfonts reliably — list system fonts in fallback order."},"button_radius":{"type":"string","description":"CSS length value for button border-radius (e.g. \"6px\", \"0\", \"9999px\" for fully round)."},"container_max_width":{"type":"string","description":"Maximum width of the email card. Bulletproof tables max-out at this."},"footer_html":{"type":"string","description":"Custom HTML to render in the email footer. Inline styles only — no <style> tags. Used by templates that opt into `{{> bp.footer}}`."},"footer_address":{"type":"string","description":"Postal address line for compliance footers (CAN-SPAM, etc.). Plain text, displayed verbatim."},"social_links":{"type":"object","description":"Map of social-platform → URL. Recognized keys: twitter, x, linkedin, github, instagram, facebook, youtube, tiktok, mastodon, bluesky, web. Keys are stored and returned exactly as sent.","additionalProperties":{"type":"string"}},"extras":{"type":"object","description":"Extra key/value tokens addressable as {{brand.extras.<key>}} in templates. Use for marketing strings, secondary accent colors, etc. Keys are stored and returned exactly as sent (`hero_title` stays `hero_title`, `heroTitle` stays `heroTitle`), so `<key>` is the key you sent.","additionalProperties":{"type":"string"},"example":{"hero_title":"Spring sale"}}}},"DeliverabilityVerdict":{"type":"string","enum":["no_data","healthy","unconfirmed","degraded","blocked"]},"DeliverabilityBlockSignalDto":{"type":"object","properties":{"detail":{"type":"string","description":"The remote diagnostic that matched a block signature.","example":"554 5.7.1 Blocked using Proofpoint Dynamic Reputation"},"count":{"type":"number","description":"How many messages carried it.","example":37}},"required":["detail","count"],"x-pc-sdk-model":"DeliverabilityBlockSignal"},"DomainStatus":{"type":"string","enum":["pending","active","disabled"]},"DmarcRecordLocation":{"type":"string","enum":["subdomain","organizational","none"]},"DmarcPolicy":{"type":"string","enum":["none","quarantine","reject"]},"DmarcAlignmentMode":{"type":"string","enum":["r","s"]},"DmarcGradeDto":{"type":"object","properties":{"location":{"description":"`subdomain`: `_dmarc.<fqdn>` exists. `organizational`: inherited from a parent domain. `none`: no policy applies.","allOf":[{"$ref":"#/components/schemas/DmarcRecordLocation"}]},"host":{"type":"string","nullable":true,"description":"Name the governing record was found at.","example":"_dmarc.example.com"},"record":{"type":"string","nullable":true,"description":"The record as published.","example":"v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"},"policy":{"nullable":true,"description":"Policy that applies to mail from this domain (`sp=` when inherited from a parent that sets it).","allOf":[{"$ref":"#/components/schemas/DmarcPolicy"}]},"domain_policy":{"nullable":true,"description":"`p=` of the record.","allOf":[{"$ref":"#/components/schemas/DmarcPolicy"}]},"subdomain_policy":{"nullable":true,"description":"`sp=` of the record, if set.","allOf":[{"$ref":"#/components/schemas/DmarcPolicy"}]},"adkim":{"nullable":true,"description":"DKIM alignment mode (`r` relaxed, the default).","allOf":[{"$ref":"#/components/schemas/DmarcAlignmentMode"}]},"aspf":{"nullable":true,"description":"SPF alignment mode (`r` relaxed, the default).","allOf":[{"$ref":"#/components/schemas/DmarcAlignmentMode"}]},"pct":{"type":"integer","nullable":true,"description":"`pct=` (100 when absent).","example":100},"rua":{"description":"Aggregate-report destinations (`rua=`).","example":["mailto:dmarc@example.com"],"type":"array","items":{"type":"string"}},"warning":{"type":"string","nullable":true,"description":"What needs attention, if anything (e.g. no policy at all: Gmail/Yahoo bulk-sender rules require DMARC)."}},"required":["location","host","record","policy","domain_policy","subdomain_policy","adkim","aspf","pct","rua","warning"],"x-pc-sdk-model":"DmarcGrade"},"DeliverabilityDomainDto":{"type":"object","properties":{"fqdn":{"type":"string","description":"The domain name.","example":"mail.example.com"},"status":{"description":"Verification status of the domain.","allOf":[{"$ref":"#/components/schemas/DomainStatus"}]},"dmarc":{"nullable":true,"description":"The DMARC policy that governs the domain, from its last DNS check; null before the first.","allOf":[{"$ref":"#/components/schemas/DmarcGradeDto"}]}},"required":["fqdn","status","dmarc"],"x-pc-sdk-model":"DeliverabilityDomain"},"DeliverabilityDto":{"type":"object","properties":{"verdict":{"description":"Overall verdict. `unconfirmed` is NOT a synonym for healthy: it means mail was handed off and nothing came back in either direction, which is the shape a blackholed sender makes. `healthy` requires positive recipient-side evidence.","example":"unconfirmed","allOf":[{"$ref":"#/components/schemas/DeliverabilityVerdict"}]},"window_days":{"type":"number","description":"Lookback used, in days.","example":14},"left_queue":{"type":"number","description":"Messages handed off for delivery in the window.","example":80},"queued":{"type":"number","description":"Messages still waiting to be handed off.","example":0},"confirmed":{"type":"number","description":"Messages with recipient-side evidence of arrival. Zero across the estate today — nothing emits that evidence yet, and reporting zero is the honest answer rather than assuming success.","example":0},"negative":{"type":"number","description":"bounced + complained + failed + deferred.","example":7},"deferred":{"type":"number","description":"Messages currently deferred.","example":235},"bounced":{"type":"number","description":"Messages hard-bounced.","example":7},"negative_rate":{"type":"number","description":"negative / left_queue.","example":0.0875},"confirmed_rate":{"type":"number","description":"confirmed / left_queue.","example":0},"block_signals":{"description":"Diagnostics that matched a known reputation-block signature.","type":"array","items":{"$ref":"#/components/schemas/DeliverabilityBlockSignalDto"}},"summary":{"type":"string","description":"One actionable sentence.","example":"80 message(s) were handed off and none has been confirmed as arriving."},"domains":{"description":"Each sending domain with its DMARC grade. Gmail and Yahoo require DMARC from bulk senders, so a domain with `dmarc.location = none` is a deliverability risk regardless of the verdict.","type":"array","items":{"$ref":"#/components/schemas/DeliverabilityDomainDto"}}},"required":["verdict","window_days","left_queue","queued","confirmed","negative","deferred","bounced","negative_rate","confirmed_rate","block_signals","summary","domains"],"x-pc-sdk-model":"Deliverability"},"MessageSource":{"type":"string","enum":["api_key","dashboard","platform","test_send"]},"MessageStatus":{"type":"string","enum":["queued","sent","delivered","bounced","complained","failed","suppressed","deferred"]},"BounceType":{"type":"string","enum":["Permanent","Transient","Undetermined"]},"MessageTransport":{"type":"string","enum":["smtp","ses"]},"EmailTagDto":{"type":"object","properties":{"name":{"type":"string","description":"Tag name: ASCII letters, digits, `_` and `-`, up to 256 characters.","maxLength":256,"pattern":"^[A-Za-z0-9_-]+$","example":"category"},"value":{"type":"string","description":"Tag value: ASCII letters, digits, `_` and `-`, up to 256 characters.","maxLength":256,"pattern":"^[A-Za-z0-9_-]+$","example":"confirm_email"}},"required":["name","value"],"x-pc-sdk-model":"EmailTag"},"OutboundMessageDto":{"type":"object","properties":{"id":{"type":"string","description":"The message id.","format":"uuid"},"workspace_id":{"type":"string","description":"The workspace that sent the message.","format":"uuid"},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain (`domain.id`). Null for rows whose domain was deleted."},"api_key_id":{"type":"string","format":"uuid","nullable":true,"description":"The Platform API Key that sent the message. Null for console, platform, MCP and test sends without a key, and unknown (null) for messages created before 2026-10-12.","example":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"},"source":{"description":"How the message was sent: `api_key`, `dashboard`, `platform` or `test_send`. Unknown for messages created before 2026-10-12, which all read `platform`.","example":"api_key","allOf":[{"$ref":"#/components/schemas/MessageSource"}]},"from_address":{"type":"string","description":"The sender address."},"to_address":{"type":"string","description":"The recipient address."},"subject":{"type":"string","description":"Subject line; null when the message has none.","nullable":true},"template_name":{"type":"string","description":"Template the message was rendered from; null for a raw send.","nullable":true},"status":{"description":"Delivery status of the message.","allOf":[{"$ref":"#/components/schemas/MessageStatus"}]},"smtp_transcript":{"type":"string","description":"SMTP conversation with the receiving server; null when not recorded.","nullable":true},"spf_result":{"type":"string","description":"SPF result reported for the delivery; null when unknown.","nullable":true},"dkim_result":{"type":"string","description":"DKIM result reported for the delivery; null when unknown.","nullable":true},"dmarc_result":{"type":"string","description":"DMARC result reported for the delivery; null when unknown.","nullable":true},"bounce_code":{"type":"string","description":"SMTP status code of a bounce; null when the message did not bounce.","nullable":true},"bounce_detail":{"type":"string","description":"Diagnostic text of a bounce; null when the message did not bounce.","nullable":true},"bounce_type":{"nullable":true,"description":"Bounce type, when the message bounced or was deferred: `Permanent`, `Transient` or `Undetermined`. `Permanent` adds the recipient to the suppression list.","example":"Permanent","allOf":[{"$ref":"#/components/schemas/BounceType"}]},"bounce_subtype":{"type":"string","nullable":true,"description":"Bounce subtype, e.g. `General`, `NoEmail`, `Suppressed`, `MailboxFull`.","example":"General"},"transport":{"nullable":true,"description":"How the message was sent: `ses` (delivery tracking: delivery, bounces and complaints reported) or `smtp` (sent before delivery tracking started or through a custom SMTP relay: hand-off confirmed, delivery not measurable). Null until the send is acknowledged.","example":"ses","allOf":[{"$ref":"#/components/schemas/MessageTransport"}]},"created_at":{"type":"string","description":"When the message was accepted for delivery.","format":"date-time"},"sent_at":{"type":"string","format":"date-time","nullable":true,"description":"When the message was handed off for delivery. This is the fact the send path actually establishes."},"delivered_at":{"type":"string","format":"date-time","nullable":true,"description":"When the message was confirmed delivered to the recipient. Null unless there is recipient-side evidence — a hand-off is not delivery."},"deferred_at":{"type":"string","format":"date-time","nullable":true,"description":"Most recent deferral. Set when the destination refused to take the message for now and delivery is still being retried."},"deferral_count":{"type":"number","description":"How many times a destination has refused to take this message. The count is the operator-legible number, not the flag: one greylist is noise, a dozen on the same recipient is a reputation block.","example":0},"email_id":{"type":"string","format":"uuid","nullable":true,"description":"The email (`POST /emails` or a template send) this message belongs to: one email, one message per recipient (`GET /emails/{id}`). Null for messages sent before 2026-11-06."},"cc":{"nullable":true,"description":"The email's Cc list, as sent; null when none.","type":"array","items":{"type":"string"}},"bcc":{"nullable":true,"description":"The email's Bcc list, as sent; null when none.","type":"array","items":{"type":"string"}},"reply_to":{"nullable":true,"description":"The email's Reply-To list, as sent; null when none.","type":"array","items":{"type":"string"}},"tags":{"nullable":true,"description":"The email's tags (`[{ name, value }]`); null when none.","type":"array","items":{"$ref":"#/components/schemas/EmailTagDto"}}},"required":["id","workspace_id","domain_id","api_key_id","source","from_address","to_address","subject","template_name","status","smtp_transcript","spf_result","dkim_result","dmarc_result","bounce_code","bounce_detail","bounce_type","bounce_subtype","transport","created_at","sent_at","delivered_at","deferred_at","deferral_count","email_id","cc","bcc","reply_to","tags"],"x-pc-sdk-model":"OutboundMessage"},"OutboundMessagePaginationDto":{"type":"object","properties":{"has_more":{"type":"boolean","description":"True iff another page exists; if true, pass `next_cursor` on the next request."},"next_cursor":{"type":"string","description":"Opaque cursor for the next page; null when no more pages.","nullable":true}},"required":["has_more","next_cursor"],"x-pc-sdk-model":"OutboundMessagePagination"},"ListOutboundMessagesResponseDto":{"type":"object","properties":{"data":{"description":"The messages on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/OutboundMessageDto"}},"pagination":{"$ref":"#/components/schemas/OutboundMessagePaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListOutboundMessages"},"OutboundMessageSettingsDto":{"type":"object","properties":{"workspace_id":{"type":"string","description":"The workspace the settings belong to.","format":"uuid"},"redact_bodies":{"type":"boolean","description":"When true, message bodies are not stored: `messages.body` returns nothing for new sends."}},"required":["workspace_id","redact_bodies"],"x-pc-sdk-model":"OutboundMessageSettings"},"UpdateOutboundMessageSettingsDto":{"type":"object","properties":{"redact_bodies":{"type":"boolean","description":"When true, messages sent from now on are logged without their body (nothing is stored), and /messages/:id/body returns null body_html + body_text even to callers with mail.message.body.read. Turn it on for workspaces whose mail carries single-use links or codes. Turning it off later does not bring back bodies of messages sent while it was on. Defaults to false."}},"required":["redact_bodies"]},"MessageEventType":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","complained","failed","suppressed"]},"MessageEventDto":{"type":"object","properties":{"id":{"type":"string","description":"The event id.","format":"uuid"},"type":{"description":"What happened. `sent` = handed off for delivery; `delivered` = the recipient's mail server accepted it (mail with delivery tracking only); `deferred` = temporarily refused, still retrying; `bounced` = permanently refused; `complained` = marked as spam; `failed` = could not be sent because of an error.","example":"delivered","allOf":[{"$ref":"#/components/schemas/MessageEventType"}]},"occurred_at":{"type":"string","format":"date-time","description":"When it happened, as reported by the source."},"detail":{"type":"object","additionalProperties":true,"description":"Source-specific detail: `source` (`relay` / `relay_accept` for untracked mail, `ses_accept` / `ses` for mail with delivery tracking), and where known `smtp_response`, `smtp_code`, `diagnostic_code`, `bounce_type`, `bounce_subtype`, `remote_mta`, `reporting_mta`, `feedback_type`, `reason`.","example":{"source":"ses","smtp_response":"250 2.0.0 OK","remote_mta":"203.0.113.7"}}},"required":["id","type","occurred_at","detail"],"x-pc-sdk-model":"MessageEvent"},"OutboundMessageDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"The message id.","format":"uuid"},"workspace_id":{"type":"string","description":"The workspace that sent the message.","format":"uuid"},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain (`domain.id`). Null for rows whose domain was deleted."},"api_key_id":{"type":"string","format":"uuid","nullable":true,"description":"The Platform API Key that sent the message. Null for console, platform, MCP and test sends without a key, and unknown (null) for messages created before 2026-10-12.","example":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"},"source":{"description":"How the message was sent: `api_key`, `dashboard`, `platform` or `test_send`. Unknown for messages created before 2026-10-12, which all read `platform`.","example":"api_key","allOf":[{"$ref":"#/components/schemas/MessageSource"}]},"from_address":{"type":"string","description":"The sender address."},"to_address":{"type":"string","description":"The recipient address."},"subject":{"type":"string","description":"Subject line; null when the message has none.","nullable":true},"template_name":{"type":"string","description":"Template the message was rendered from; null for a raw send.","nullable":true},"status":{"description":"Delivery status of the message.","allOf":[{"$ref":"#/components/schemas/MessageStatus"}]},"smtp_transcript":{"type":"string","description":"SMTP conversation with the receiving server; null when not recorded.","nullable":true},"spf_result":{"type":"string","description":"SPF result reported for the delivery; null when unknown.","nullable":true},"dkim_result":{"type":"string","description":"DKIM result reported for the delivery; null when unknown.","nullable":true},"dmarc_result":{"type":"string","description":"DMARC result reported for the delivery; null when unknown.","nullable":true},"bounce_code":{"type":"string","description":"SMTP status code of a bounce; null when the message did not bounce.","nullable":true},"bounce_detail":{"type":"string","description":"Diagnostic text of a bounce; null when the message did not bounce.","nullable":true},"bounce_type":{"nullable":true,"description":"Bounce type, when the message bounced or was deferred: `Permanent`, `Transient` or `Undetermined`. `Permanent` adds the recipient to the suppression list.","example":"Permanent","allOf":[{"$ref":"#/components/schemas/BounceType"}]},"bounce_subtype":{"type":"string","nullable":true,"description":"Bounce subtype, e.g. `General`, `NoEmail`, `Suppressed`, `MailboxFull`.","example":"General"},"transport":{"nullable":true,"description":"How the message was sent: `ses` (delivery tracking: delivery, bounces and complaints reported) or `smtp` (sent before delivery tracking started or through a custom SMTP relay: hand-off confirmed, delivery not measurable). Null until the send is acknowledged.","example":"ses","allOf":[{"$ref":"#/components/schemas/MessageTransport"}]},"created_at":{"type":"string","description":"When the message was accepted for delivery.","format":"date-time"},"sent_at":{"type":"string","format":"date-time","nullable":true,"description":"When the message was handed off for delivery. This is the fact the send path actually establishes."},"delivered_at":{"type":"string","format":"date-time","nullable":true,"description":"When the message was confirmed delivered to the recipient. Null unless there is recipient-side evidence — a hand-off is not delivery."},"deferred_at":{"type":"string","format":"date-time","nullable":true,"description":"Most recent deferral. Set when the destination refused to take the message for now and delivery is still being retried."},"deferral_count":{"type":"number","description":"How many times a destination has refused to take this message. The count is the operator-legible number, not the flag: one greylist is noise, a dozen on the same recipient is a reputation block.","example":0},"email_id":{"type":"string","format":"uuid","nullable":true,"description":"The email (`POST /emails` or a template send) this message belongs to: one email, one message per recipient (`GET /emails/{id}`). Null for messages sent before 2026-11-06."},"cc":{"nullable":true,"description":"The email's Cc list, as sent; null when none.","type":"array","items":{"type":"string"}},"bcc":{"nullable":true,"description":"The email's Bcc list, as sent; null when none.","type":"array","items":{"type":"string"}},"reply_to":{"nullable":true,"description":"The email's Reply-To list, as sent; null when none.","type":"array","items":{"type":"string"}},"tags":{"nullable":true,"description":"The email's tags (`[{ name, value }]`); null when none.","type":"array","items":{"$ref":"#/components/schemas/EmailTagDto"}},"events":{"description":"Every recorded transition, oldest first (at most 200).","type":"array","items":{"$ref":"#/components/schemas/MessageEventDto"}},"last_event":{"nullable":true,"description":"The most recent event, or null for a row that predates event recording.","allOf":[{"$ref":"#/components/schemas/MessageEventDto"}]}},"required":["id","workspace_id","domain_id","api_key_id","source","from_address","to_address","subject","template_name","status","smtp_transcript","spf_result","dkim_result","dmarc_result","bounce_code","bounce_detail","bounce_type","bounce_subtype","transport","created_at","sent_at","delivered_at","deferred_at","deferral_count","email_id","cc","bcc","reply_to","tags","events","last_event"],"x-pc-sdk-model":"OutboundMessageDetail"},"OutboundMessageWithBodyDto":{"type":"object","properties":{"id":{"type":"string","description":"The message id.","format":"uuid"},"workspace_id":{"type":"string","description":"The workspace that sent the message.","format":"uuid"},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain (`domain.id`). Null for rows whose domain was deleted."},"api_key_id":{"type":"string","format":"uuid","nullable":true,"description":"The Platform API Key that sent the message. Null for console, platform, MCP and test sends without a key, and unknown (null) for messages created before 2026-10-12.","example":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"},"source":{"description":"How the message was sent: `api_key`, `dashboard`, `platform` or `test_send`. Unknown for messages created before 2026-10-12, which all read `platform`.","example":"api_key","allOf":[{"$ref":"#/components/schemas/MessageSource"}]},"from_address":{"type":"string","description":"The sender address."},"to_address":{"type":"string","description":"The recipient address."},"subject":{"type":"string","description":"Subject line; null when the message has none.","nullable":true},"template_name":{"type":"string","description":"Template the message was rendered from; null for a raw send.","nullable":true},"status":{"description":"Delivery status of the message.","allOf":[{"$ref":"#/components/schemas/MessageStatus"}]},"smtp_transcript":{"type":"string","description":"SMTP conversation with the receiving server; null when not recorded.","nullable":true},"spf_result":{"type":"string","description":"SPF result reported for the delivery; null when unknown.","nullable":true},"dkim_result":{"type":"string","description":"DKIM result reported for the delivery; null when unknown.","nullable":true},"dmarc_result":{"type":"string","description":"DMARC result reported for the delivery; null when unknown.","nullable":true},"bounce_code":{"type":"string","description":"SMTP status code of a bounce; null when the message did not bounce.","nullable":true},"bounce_detail":{"type":"string","description":"Diagnostic text of a bounce; null when the message did not bounce.","nullable":true},"bounce_type":{"nullable":true,"description":"Bounce type, when the message bounced or was deferred: `Permanent`, `Transient` or `Undetermined`. `Permanent` adds the recipient to the suppression list.","example":"Permanent","allOf":[{"$ref":"#/components/schemas/BounceType"}]},"bounce_subtype":{"type":"string","nullable":true,"description":"Bounce subtype, e.g. `General`, `NoEmail`, `Suppressed`, `MailboxFull`.","example":"General"},"transport":{"nullable":true,"description":"How the message was sent: `ses` (delivery tracking: delivery, bounces and complaints reported) or `smtp` (sent before delivery tracking started or through a custom SMTP relay: hand-off confirmed, delivery not measurable). Null until the send is acknowledged.","example":"ses","allOf":[{"$ref":"#/components/schemas/MessageTransport"}]},"created_at":{"type":"string","description":"When the message was accepted for delivery.","format":"date-time"},"sent_at":{"type":"string","format":"date-time","nullable":true,"description":"When the message was handed off for delivery. This is the fact the send path actually establishes."},"delivered_at":{"type":"string","format":"date-time","nullable":true,"description":"When the message was confirmed delivered to the recipient. Null unless there is recipient-side evidence — a hand-off is not delivery."},"deferred_at":{"type":"string","format":"date-time","nullable":true,"description":"Most recent deferral. Set when the destination refused to take the message for now and delivery is still being retried."},"deferral_count":{"type":"number","description":"How many times a destination has refused to take this message. The count is the operator-legible number, not the flag: one greylist is noise, a dozen on the same recipient is a reputation block.","example":0},"email_id":{"type":"string","format":"uuid","nullable":true,"description":"The email (`POST /emails` or a template send) this message belongs to: one email, one message per recipient (`GET /emails/{id}`). Null for messages sent before 2026-11-06."},"cc":{"nullable":true,"description":"The email's Cc list, as sent; null when none.","type":"array","items":{"type":"string"}},"bcc":{"nullable":true,"description":"The email's Bcc list, as sent; null when none.","type":"array","items":{"type":"string"}},"reply_to":{"nullable":true,"description":"The email's Reply-To list, as sent; null when none.","type":"array","items":{"type":"string"}},"tags":{"nullable":true,"description":"The email's tags (`[{ name, value }]`); null when none.","type":"array","items":{"$ref":"#/components/schemas/EmailTagDto"}},"body_html":{"type":"string","nullable":true,"description":"Cleartext HTML body. Null when the workspace has `redact_bodies = true`."},"body_text":{"type":"string","nullable":true,"description":"Cleartext text body. Null when the workspace has `redact_bodies = true`."}},"required":["id","workspace_id","domain_id","api_key_id","source","from_address","to_address","subject","template_name","status","smtp_transcript","spf_result","dkim_result","dmarc_result","bounce_code","bounce_detail","bounce_type","bounce_subtype","transport","created_at","sent_at","delivered_at","deferred_at","deferral_count","email_id","cc","bcc","reply_to","tags","body_html","body_text"],"x-pc-sdk-model":"OutboundMessageWithBody"},"DeleteByRecipientResponseDto":{"type":"object","properties":{"deleted":{"type":"number","description":"Number of rows deleted."}},"required":["deleted"],"x-pc-sdk-model":"DeleteByRecipient"},"DomainCapabilitiesInputDto":{"type":"object","properties":{"sending":{"type":"string","enum":["enabled","disabled"],"description":"Send from this domain. Create: defaults to `enabled`. Update: omitted keeps the current value."},"receiving":{"type":"string","enum":["enabled","disabled"],"description":"Receive mail at this domain (its MX points at ProductCraft). Create: defaults to `disabled`. Update: omitted keeps the current value."}}},"CreateDomainDto":{"type":"object","properties":{"tls":{"type":"string","enum":["opportunistic","enforced"],"default":"opportunistic","description":"`opportunistic` only for now (TLS whenever the receiver offers it); `enforced` is refused with 422 `TLS_ENFORCED_NOT_AVAILABLE`."},"open_tracking":{"type":"boolean","description":"Only `false` for now; `true` is refused with 422 `TRACKING_NOT_AVAILABLE`.","example":false},"click_tracking":{"type":"boolean","description":"Only `false` for now; `true` is refused with 422 `TRACKING_NOT_AVAILABLE`.","example":false},"tracking_subdomain":{"type":"string","description":"Not available yet: any value is refused with 422 `TRACKING_NOT_AVAILABLE`.","maxLength":63},"fqdn":{"type":"string","description":"Fully qualified domain name. Required unless `name` is sent.","example":"mail.example.com"},"name":{"type":"string","description":"Resend's name for `fqdn`. Send either; both must agree when both are sent.","example":"mail.example.com"},"intent":{"type":"string","description":"How the workspace plans to use this domain; drives which DNS records gate verification. Defaults to `send` (Resend's default: sending on, receiving off). Same as `capabilities`; send one or the other, or both in agreement.","enum":["receive","send","both"],"default":"send"},"capabilities":{"description":"Resend's shape of `intent`: `sending` defaults to `enabled`, `receiving` to `disabled`; at least one must be enabled.","allOf":[{"$ref":"#/components/schemas/DomainCapabilitiesInputDto"}]},"region":{"type":"string","description":"The AWS region to send from. Every domain of this deployment sends from the same region (`region` on any domain, e.g. `eu-north-1`); any other value is refused with 422 `REGION_NOT_AVAILABLE`.","example":"eu-north-1"},"custom_return_path":{"type":"string","description":"Resend's name for `mail_from_subdomain`: the custom MAIL FROM (return-path) label, `bounce` → `bounce.<fqdn>`. Sending domains only; defaults to `bounce`. Refused with 409 `MAIL_FROM_HOST_IN_USE` when that host already has records that are not ours.","example":"bounce","maxLength":63}}},"DomainIntent":{"type":"string","enum":["receive","send","both"]},"DomainCapabilityState":{"type":"string","enum":["enabled","disabled"]},"DomainCapabilitiesDto":{"type":"object","properties":{"sending":{"example":"enabled","description":"Sending from this domain (DKIM signing).","allOf":[{"$ref":"#/components/schemas/DomainCapabilityState"}]},"receiving":{"example":"disabled","description":"Receiving mail at this domain (MX pointed at ProductCraft).","allOf":[{"$ref":"#/components/schemas/DomainCapabilityState"}]}},"required":["sending","receiving"],"x-pc-sdk-model":"DomainCapabilities"},"DomainTlsMode":{"type":"string","enum":["opportunistic"]},"DomainHealth":{"type":"string","enum":["ok","degraded","failing"]},"DnsProviderSource":{"type":"string","enum":["user","detected"]},"DomainDnsProviderDto":{"type":"object","properties":{"id":{"type":"string","description":"Provider id (the console's provider guides use the same ids). A user-chosen id we do not know is returned as chosen.","example":"digitalocean"},"name":{"type":"string","description":"Display name; `Other` for an id we have no name for.","example":"DigitalOcean"},"source":{"description":"`user`: chosen in the setup wizard (PATCH `dns_provider`). `detected`: from the zone's NS records when the domain was added.","example":"detected","allOf":[{"$ref":"#/components/schemas/DnsProviderSource"}]}},"required":["id","name","source"],"x-pc-sdk-model":"DomainDnsProvider"},"DnsProviderId":{"type":"string","enum":["cloudflare","digitalocean","namecheap","godaddy","squarespace","route53","porkbun","vercel","netlify","gandi","hover","other"]},"DomainVerificationStatus":{"type":"string","enum":["not_started","pending","partially_verified","verified","temporary_failure","failed","disabled"]},"SesDkimStatus":{"type":"string","enum":["PENDING","SUCCESS","FAILED","TEMPORARY_FAILURE","NOT_STARTED","not_enabled"]},"SesMailFromStatus":{"type":"string","enum":["PENDING","SUCCESS","FAILED","TEMPORARY_FAILURE"]},"DomainSetupMethod":{"type":"string","enum":["manual","domain_connect","provider_api"]},"DnsRecordPurpose":{"type":"string","enum":["dkim","mx","verification","spf","mail_from_mx","mail_from_spf","dmarc"]},"DnsRecordType":{"type":"string","enum":["TXT","MX"]},"DnsInstructionDto":{"type":"object","properties":{"purpose":{"description":"What the record is for: `dkim` (signing key; also the ownership proof for sending domains), `mx` (inbound routing, receive/both only), `verification` (ownership token, receive-only domains), `spf` (legacy From-domain SPF, informational), `mail_from_mx` / `mail_from_spf` (custom MAIL FROM host, recommended), `dmarc` (recommended only while no DMARC policy applies to the domain).","example":"dkim","allOf":[{"$ref":"#/components/schemas/DnsRecordPurpose"}]},"type":{"description":"Record type.","example":"TXT","allOf":[{"$ref":"#/components/schemas/DnsRecordType"}]},"host":{"type":"string","description":"Fully qualified DNS name to publish the record at.","example":"productcraft._domainkey.mail.example.com"},"value":{"type":"string","description":"Record value the customer must publish."},"ttl":{"type":"number","description":"TTL hint (in seconds)."},"priority":{"type":"number","description":"Priority for MX records."},"required":{"type":"boolean","description":"Whether this record must pass before the domain goes `active` for its intent. `false` means informational or recommended: reported, never blocking.","example":true}},"required":["purpose","type","host","value","required"],"x-pc-sdk-model":"DnsInstruction"},"DomainRecordKind":{"type":"string","enum":["DKIM","SPF","MX","DMARC","Verification"]},"DomainRecordStatus":{"type":"string","enum":["not_started","pending","verified","failed","temporary_failure"]},"DomainRecordDto":{"type":"object","properties":{"record":{"description":"What the record is for, in Resend's words: `DKIM` (signing key), `SPF` (the return-path MX + TXT, and a legacy From-domain SPF), `MX` (receiving), `DMARC`, `Verification` (ownership token of a receive-only domain).","example":"DKIM","allOf":[{"$ref":"#/components/schemas/DomainRecordKind"}]},"purpose":{"description":"Our record id (`purpose` in `dns_instructions` and `GET .../dns-records`).","example":"dkim","allOf":[{"$ref":"#/components/schemas/DnsRecordPurpose"}]},"name":{"type":"string","description":"Host to publish at, relative to the zone (`@` for the zone apex); the full name when the zone is not known yet.","example":"productcraft._domainkey.mail"},"type":{"description":"DNS record type.","example":"TXT","allOf":[{"$ref":"#/components/schemas/DnsRecordType"}]},"value":{"type":"string","description":"Record value. MX: the mail server host; the preference is `priority`."},"priority":{"type":"integer","description":"MX preference; MX records only.","example":10},"ttl":{"type":"integer","description":"TTL to publish with, in seconds.","example":3600},"status":{"description":"`not_started`: the domain has not been checked yet. `pending`: not seen yet, or still propagating. `verified`: seen as expected. `failed`: a different value, or a conflicting record, is published. `temporary_failure`: a required record of a verified domain went missing or changed. Detail per record: `GET .../dns-records`.","example":"verified","allOf":[{"$ref":"#/components/schemas/DomainRecordStatus"}]},"required":{"type":"boolean","description":"Whether this record gates verification (`false`: recommended or informational).","example":true}},"required":["record","purpose","name","type","value","ttl","status","required"],"x-pc-sdk-model":"DomainRecord"},"DomainDto":{"type":"object","properties":{"id":{"type":"string","description":"The domain id.","format":"uuid"},"seq_id":{"type":"string","description":"Sequential id per workspace.","example":"3"},"workspace_id":{"type":"string","description":"The workspace that owns the domain.","format":"uuid"},"owner_account_id":{"type":"string","description":"Platform account that added the domain; null when added with an API key.","format":"uuid","nullable":true},"fqdn":{"type":"string","description":"The domain name.","example":"productcraft.co"},"name":{"type":"string","description":"Same as `fqdn` (Resend's field name).","example":"productcraft.co"},"intent":{"description":"How the workspace uses this domain; `capabilities` is the same thing in Resend's shape. Changeable with PATCH.","allOf":[{"$ref":"#/components/schemas/DomainIntent"}]},"capabilities":{"$ref":"#/components/schemas/DomainCapabilitiesDto"},"tls":{"description":"TLS on delivery to the receiving server. Always `opportunistic` today (TLS whenever the receiver offers it); `enforced` is not available yet.","example":"opportunistic","allOf":[{"$ref":"#/components/schemas/DomainTlsMode"}]},"open_tracking":{"type":"boolean","description":"Open tracking. Always false: tracking is not available yet.","example":false},"click_tracking":{"type":"boolean","description":"Click tracking. Always false: tracking is not available yet.","example":false},"tracking_subdomain":{"type":"string","nullable":true,"description":"Tracking subdomain. Always null: tracking is not available yet.","example":null},"status":{"description":"Verification status: `pending` until the required records verify, then `active`; `disabled` when switched off.","example":"pending","allOf":[{"$ref":"#/components/schemas/DomainStatus"}]},"health":{"example":"ok","description":"Drift on a verified domain. `degraded`: a required record (DKIM, or MX for receiving) went missing or changed, or DKIM signing no longer verifies; mail still flows and workspace owners are emailed. `failing`: still degraded 72 h later; sends from the domain are refused with 422 `domain_not_verified_by_provider`. Back to `ok` as soon as the records are. A failed DNS lookup never changes it, and recommended records (MAIL FROM, DMARC) never do. Always `ok` while the domain is not `active`.","allOf":[{"$ref":"#/components/schemas/DomainHealth"}]},"health_changed_at":{"type":"string","format":"date-time","nullable":true,"description":"When `health` last changed; null if it has always been `ok`."},"health_grace_ends_at":{"type":"string","format":"date-time","nullable":true,"description":"While `health` is `degraded`: when the 72 h grace ends and the domain becomes `failing` unless the records are back. Null otherwise."},"verification_token":{"type":"string","nullable":true,"description":"Ownership token for the `_productcraft-verify` TXT. Issued for receive-only domains; sending domains prove ownership with their DKIM record, so it is null for send/both domains created since 2026-10."},"test_token":{"type":"string","description":"Token in the domain's test address (`test-<token>@<domain>`); a mail sent there proves receiving works."},"test_received_at":{"type":"string","description":"When a test mail to the test address last arrived; null if none yet.","format":"date-time","nullable":true},"dkim_selector":{"type":"string","description":"DKIM selector the domain signs with; null until DKIM is set up.","nullable":true},"dkim_public_key":{"type":"string","nullable":true,"description":"Public DKIM key in PEM form (private half stays server-side)."},"dns_provider":{"nullable":true,"description":"The effective DNS provider: the user's choice when set, otherwise the one detected from the zone's NS records; null when neither is known. Changed in 2026-10 from the raw id string, which is now `dns_provider_id`.","allOf":[{"$ref":"#/components/schemas/DomainDnsProviderDto"}]},"dns_provider_id":{"type":"string","nullable":true,"deprecated":true,"description":"The provider id chosen in the setup wizard (PATCH `dns_provider`), or null when not chosen. Kept for one release for clients that read the old string `dns_provider`; use `dns_provider.id`.","example":"cloudflare"},"dns_provider_detected":{"nullable":true,"description":"DNS provider detected from the zone's NS records when the domain was added; `dns_provider` reports the effective one.","allOf":[{"$ref":"#/components/schemas/DnsProviderId"}]},"verification_status":{"example":"pending","description":"One status in Resend's vocabulary, derived from `status`, `health`, `intent` and the record states; first match wins. `disabled`: the domain is disabled. `failed`: `health` is `failing`, or still pending 72 h after it was added. `temporary_failure`: verified, but a required record went missing or changed (`health = degraded`, within the 72 h grace). `verified`: active and healthy. `partially_verified`: a send + receive domain where exactly one of sending (DKIM, and DKIM signing) and receiving (MX) verifies. `pending`: checked at least once, not verified yet. `not_started`: not checked yet. Recommended records (MAIL FROM, DMARC) never change it; see `recommended_pending`.","allOf":[{"$ref":"#/components/schemas/DomainVerificationStatus"}]},"recommended_pending":{"type":"integer","minimum":0,"example":2,"description":"Recommended records (custom MAIL FROM MX + SPF, DMARC) that are not verified yet. Informational; they never block the domain."},"region":{"type":"string","nullable":true,"example":"eu-north-1","description":"The region mail from this domain is sent from, e.g. `eu-north-1`. Read-only and the same for every domain of this deployment; null when not configured."},"region_name":{"type":"string","nullable":true,"example":"Stockholm","description":"Display name of `region`."},"dns_check_results":{"type":"object","additionalProperties":true,"nullable":true,"description":"Snapshot of the most recent DNS check, as recorded by the checker (its keys are not a stable contract; `GET .../dns-records` returns the typed per-record results)."},"last_dns_check_at":{"type":"string","description":"When the DNS records were last checked; null if never.","format":"date-time","nullable":true},"dns_zone":{"type":"string","nullable":true,"format":"hostname","description":"Zone apex found by walking SOA records up from the fqdn; null before the first check.","example":"example.com"},"ses_dkim_status":{"nullable":true,"description":"DKIM signing verification of this domain, mirrored on every check. `not_enabled` where sending verification is off in this environment (local, preview); null while the domain is not registered for signing yet.","allOf":[{"$ref":"#/components/schemas/SesDkimStatus"}]},"mail_from_subdomain":{"type":"string","nullable":true,"description":"Custom MAIL FROM label (`bounce` → `bounce.<fqdn>`); null when off. On by default for sending domains created since 2026-10.","example":"bounce"},"mail_from_status":{"nullable":true,"description":"Verification of the custom MAIL FROM host (its MX record); null when no custom MAIL FROM is configured.","allOf":[{"$ref":"#/components/schemas/SesMailFromStatus"}]},"dmarc_managed":{"type":"boolean","description":"false when the customer opted out of our `_dmarc` recommendation (PATCH `dmarc_managed`).","example":true},"setup_method":{"nullable":true,"description":"How the DNS records were last set up by an automated path: `provider_api` after `POST .../dns-records/apply` wrote them with a provider token, `domain_connect` after a Domain Connect flow. Null when the records were (or are being) added by hand.","example":null,"allOf":[{"$ref":"#/components/schemas/DomainSetupMethod"}]},"dmarc_grade":{"nullable":true,"description":"The DMARC policy that governs this domain, graded on the last check; null before the first check of a sending domain.","allOf":[{"$ref":"#/components/schemas/DmarcGradeDto"}]},"verified_at":{"type":"string","description":"When the domain was first verified; null until then.","format":"date-time","nullable":true},"created_at":{"type":"string","description":"When the domain was added.","format":"date-time"},"dns_instructions":{"description":"DNS records to publish for this domain's intent. Records with `required: true` gate `active`; the rest are informational.","type":"array","items":{"$ref":"#/components/schemas/DnsInstructionDto"}},"records":{"description":"The same records in Resend's `records[]` shape, each with its status.","type":"array","items":{"$ref":"#/components/schemas/DomainRecordDto"}},"test_address":{"type":"string","description":"Convenience accessor for the test-email mailbox address on this domain.","example":"test-abc123@productcraft.co"}},"required":["id","seq_id","workspace_id","owner_account_id","fqdn","name","intent","capabilities","tls","open_tracking","click_tracking","tracking_subdomain","status","health","health_changed_at","health_grace_ends_at","verification_token","test_token","test_received_at","dkim_selector","dkim_public_key","dns_provider","dns_provider_id","dns_provider_detected","verification_status","recommended_pending","region","region_name","dns_check_results","last_dns_check_at","dns_zone","ses_dkim_status","mail_from_subdomain","mail_from_status","dmarc_managed","setup_method","dmarc_grade","verified_at","created_at","dns_instructions","records","test_address"],"x-pc-sdk-model":"Domain"},"PaginationDto":{"type":"object","properties":{"next_cursor":{"type":"string","description":"Opaque cursor for the next page. `null` when no more pages are available.","nullable":true,"example":"eyJjcmVhdGVkX2F0IjoiMjAyNi0wNS0wMVQwMDowMDowMFoifQ"},"has_more":{"type":"boolean","description":"True iff another page exists; if true, pass `next_cursor` on the next request.","example":false}},"required":["next_cursor","has_more"],"x-pc-sdk-model":"Pagination"},"ListDomainsResponseDto":{"type":"object","properties":{"data":{"description":"The domains on this page.","type":"array","items":{"$ref":"#/components/schemas/DomainDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListDomains"},"DnsProviderLookupSource":{"type":"string","enum":["ns","domain_connect"]},"LookupProviderDto":{"type":"object","properties":{"id":{"description":"Provider id, matching the console's provider guides.","allOf":[{"$ref":"#/components/schemas/DnsProviderId"}]},"name":{"type":"string","description":"Display name of the DNS provider.","example":"Cloudflare"},"source":{"description":"How it was identified: NS host names, or the Domain Connect settings the zone advertises.","allOf":[{"$ref":"#/components/schemas/DnsProviderLookupSource"}]},"nameservers":{"description":"The zone's nameservers that identified the provider.","example":["ns1.digitalocean.com","ns2.digitalocean.com"],"type":"array","items":{"type":"string"}}},"required":["id","name","source","nameservers"],"x-pc-sdk-model":"LookupProvider"},"DomainConnectUnavailableReason":{"type":"string","enum":["no_record","settings_unreachable","template_not_onboarded","lookup_failed","disabled"]},"LookupDomainConnectDto":{"type":"object","properties":{"available":{"type":"boolean","description":"Our Domain Connect template is onboarded at this provider: one-click setup is possible."},"supported":{"type":"boolean","description":"The zone's DNS provider runs Domain Connect at all."},"provider_id":{"type":"string","description":"Domain Connect provider id; null when the zone does not advertise one.","nullable":true,"example":"cloudflare.com"},"provider_name":{"type":"string","description":"Domain Connect provider name; null when unknown.","nullable":true,"example":"Cloudflare"},"reason":{"nullable":true,"description":"Why `available` is false: the zone advertises no Domain Connect (`no_record`), its settings could not be read (`settings_unreachable`), the provider has not onboarded our template (`template_not_onboarded`), DNS did not answer (`lookup_failed`), or the provider is ready but ProductCraft has not switched Domain Connect on yet (`disabled`).","allOf":[{"$ref":"#/components/schemas/DomainConnectUnavailableReason"}]}},"required":["available","supported","provider_id","provider_name","reason"],"x-pc-sdk-model":"LookupDomainConnect"},"LookupSuggestionDto":{"type":"object","properties":{"fqdn":{"type":"string","description":"The suggested domain name.","example":"mail.acme.com"},"reason":{"type":"string","description":"One sentence on why."}},"required":["fqdn","reason"],"x-pc-sdk-model":"LookupSuggestion"},"LookupSpfDto":{"type":"object","properties":{"host":{"type":"string","description":"Host the SPF record is published at.","example":"acme.com"},"record":{"type":"string","description":"The SPF record as published.","example":"v=spf1 include:_spf.google.com ~all"}},"required":["host","record"],"x-pc-sdk-model":"LookupSpf"},"LookupDmarcDto":{"type":"object","properties":{"host":{"type":"string","description":"Host the DMARC record is published at.","example":"_dmarc.acme.com"},"record":{"type":"string","description":"The DMARC record as published.","example":"v=DMARC1; p=none"}},"required":["host","record"],"x-pc-sdk-model":"LookupDmarc"},"LookupExistingDto":{"type":"object","properties":{"spf":{"description":"SPF records at the fqdn and at the zone apex.","type":"array","items":{"$ref":"#/components/schemas/LookupSpfDto"}},"dmarc":{"nullable":true,"description":"The DMARC record that governs the fqdn (its own, else the nearest parent).","allOf":[{"$ref":"#/components/schemas/LookupDmarcDto"}]},"dkim_selector_taken":{"type":"boolean","description":"Something already publishes a DKIM key at `productcraft._domainkey.<fqdn>`."},"mx":{"description":"MX records at the fqdn (`<priority> <host>`): who receives its mail today.","example":["10 aspmx.l.google.com"],"type":"array","items":{"type":"string"}}},"required":["spf","dmarc","dkim_selector_taken","mx"],"x-pc-sdk-model":"LookupExisting"},"DomainLookupDto":{"type":"object","properties":{"fqdn":{"type":"string","description":"The domain that was looked up.","example":"acme.com"},"zone":{"type":"string","nullable":true,"description":"Zone apex found by walking SOA records; null when the domain does not resolve.","example":"acme.com"},"provider":{"$ref":"#/components/schemas/LookupProviderDto"},"domain_connect":{"$ref":"#/components/schemas/LookupDomainConnectDto"},"suggestion":{"nullable":true,"description":"A better name to send from when an apex was typed: `mail.<apex>`, or `send.<apex>` when `mail.` already has other records.","allOf":[{"$ref":"#/components/schemas/LookupSuggestionDto"}]},"existing":{"description":"Records already there that will matter.","allOf":[{"$ref":"#/components/schemas/LookupExistingDto"}]}},"required":["fqdn","zone","provider","domain_connect","suggestion","existing"],"x-pc-sdk-model":"DomainLookup"},"DomainEventType":{"type":"string","enum":["added","records_found","verified","degraded","failing","recovered","mail_from_verified","dmarc_detected","check_failed","deleted"]},"DomainEventDto":{"type":"object","properties":{"id":{"type":"string","description":"The event id.","format":"uuid"},"domain_id":{"type":"string","description":"The domain the event is about.","format":"uuid"},"type":{"example":"verified","description":"`added`: the domain was registered. `records_found`: a required record (DKIM, MX, verification TXT) was found published. `verified`: the domain went active. `degraded` / `failing` / `recovered`: drift on a verified domain (see `health`). `mail_from_verified`: the custom MAIL FROM host was verified. `dmarc_detected`: a DMARC policy now applies to the domain. `check_failed`: a check of a pending domain found a required record published wrong (a conflicting or stale value, SES refusing the signature) or removed after it was found. Records not published yet are setup in progress, not a failure, and write nothing. `deleted`: the domain was removed. Written only when something changed; a quiet recheck adds nothing.","allOf":[{"$ref":"#/components/schemas/DomainEventType"}]},"occurred_at":{"type":"string","description":"When the event happened.","format":"date-time"},"detail":{"type":"object","additionalProperties":true,"description":"What happened, by type. `records_found` / `check_failed`: `records: [{ purpose, state }]` (`purpose` as in `dns_instructions`, plus `ses` for the DKIM signing verdict, whose `state` is that check's status). `degraded` / `failing`: `problems: string[]`. `dmarc_detected`: `location`, `host`, `policy`. `added`: `fqdn`, `intent`. `deleted`: `fqdn`. `backfilled: true` marks events reconstructed from the domain's timestamps when the timeline was introduced.","example":{"records":[{"purpose":"dkim","state":"missing"}]}}},"required":["id","domain_id","type","occurred_at","detail"],"x-pc-sdk-model":"DomainEvent"},"DomainDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"The domain id.","format":"uuid"},"seq_id":{"type":"string","description":"Sequential id per workspace.","example":"3"},"workspace_id":{"type":"string","description":"The workspace that owns the domain.","format":"uuid"},"owner_account_id":{"type":"string","description":"Platform account that added the domain; null when added with an API key.","format":"uuid","nullable":true},"fqdn":{"type":"string","description":"The domain name.","example":"productcraft.co"},"name":{"type":"string","description":"Same as `fqdn` (Resend's field name).","example":"productcraft.co"},"intent":{"description":"How the workspace uses this domain; `capabilities` is the same thing in Resend's shape. Changeable with PATCH.","allOf":[{"$ref":"#/components/schemas/DomainIntent"}]},"capabilities":{"$ref":"#/components/schemas/DomainCapabilitiesDto"},"tls":{"description":"TLS on delivery to the receiving server. Always `opportunistic` today (TLS whenever the receiver offers it); `enforced` is not available yet.","example":"opportunistic","allOf":[{"$ref":"#/components/schemas/DomainTlsMode"}]},"open_tracking":{"type":"boolean","description":"Open tracking. Always false: tracking is not available yet.","example":false},"click_tracking":{"type":"boolean","description":"Click tracking. Always false: tracking is not available yet.","example":false},"tracking_subdomain":{"type":"string","nullable":true,"description":"Tracking subdomain. Always null: tracking is not available yet.","example":null},"status":{"description":"Verification status: `pending` until the required records verify, then `active`; `disabled` when switched off.","example":"pending","allOf":[{"$ref":"#/components/schemas/DomainStatus"}]},"health":{"example":"ok","description":"Drift on a verified domain. `degraded`: a required record (DKIM, or MX for receiving) went missing or changed, or DKIM signing no longer verifies; mail still flows and workspace owners are emailed. `failing`: still degraded 72 h later; sends from the domain are refused with 422 `domain_not_verified_by_provider`. Back to `ok` as soon as the records are. A failed DNS lookup never changes it, and recommended records (MAIL FROM, DMARC) never do. Always `ok` while the domain is not `active`.","allOf":[{"$ref":"#/components/schemas/DomainHealth"}]},"health_changed_at":{"type":"string","format":"date-time","nullable":true,"description":"When `health` last changed; null if it has always been `ok`."},"health_grace_ends_at":{"type":"string","format":"date-time","nullable":true,"description":"While `health` is `degraded`: when the 72 h grace ends and the domain becomes `failing` unless the records are back. Null otherwise."},"verification_token":{"type":"string","nullable":true,"description":"Ownership token for the `_productcraft-verify` TXT. Issued for receive-only domains; sending domains prove ownership with their DKIM record, so it is null for send/both domains created since 2026-10."},"test_token":{"type":"string","description":"Token in the domain's test address (`test-<token>@<domain>`); a mail sent there proves receiving works."},"test_received_at":{"type":"string","description":"When a test mail to the test address last arrived; null if none yet.","format":"date-time","nullable":true},"dkim_selector":{"type":"string","description":"DKIM selector the domain signs with; null until DKIM is set up.","nullable":true},"dkim_public_key":{"type":"string","nullable":true,"description":"Public DKIM key in PEM form (private half stays server-side)."},"dns_provider":{"nullable":true,"description":"The effective DNS provider: the user's choice when set, otherwise the one detected from the zone's NS records; null when neither is known. Changed in 2026-10 from the raw id string, which is now `dns_provider_id`.","allOf":[{"$ref":"#/components/schemas/DomainDnsProviderDto"}]},"dns_provider_id":{"type":"string","nullable":true,"deprecated":true,"description":"The provider id chosen in the setup wizard (PATCH `dns_provider`), or null when not chosen. Kept for one release for clients that read the old string `dns_provider`; use `dns_provider.id`.","example":"cloudflare"},"dns_provider_detected":{"nullable":true,"description":"DNS provider detected from the zone's NS records when the domain was added; `dns_provider` reports the effective one.","allOf":[{"$ref":"#/components/schemas/DnsProviderId"}]},"verification_status":{"example":"pending","description":"One status in Resend's vocabulary, derived from `status`, `health`, `intent` and the record states; first match wins. `disabled`: the domain is disabled. `failed`: `health` is `failing`, or still pending 72 h after it was added. `temporary_failure`: verified, but a required record went missing or changed (`health = degraded`, within the 72 h grace). `verified`: active and healthy. `partially_verified`: a send + receive domain where exactly one of sending (DKIM, and DKIM signing) and receiving (MX) verifies. `pending`: checked at least once, not verified yet. `not_started`: not checked yet. Recommended records (MAIL FROM, DMARC) never change it; see `recommended_pending`.","allOf":[{"$ref":"#/components/schemas/DomainVerificationStatus"}]},"recommended_pending":{"type":"integer","minimum":0,"example":2,"description":"Recommended records (custom MAIL FROM MX + SPF, DMARC) that are not verified yet. Informational; they never block the domain."},"region":{"type":"string","nullable":true,"example":"eu-north-1","description":"The region mail from this domain is sent from, e.g. `eu-north-1`. Read-only and the same for every domain of this deployment; null when not configured."},"region_name":{"type":"string","nullable":true,"example":"Stockholm","description":"Display name of `region`."},"dns_check_results":{"type":"object","additionalProperties":true,"nullable":true,"description":"Snapshot of the most recent DNS check, as recorded by the checker (its keys are not a stable contract; `GET .../dns-records` returns the typed per-record results)."},"last_dns_check_at":{"type":"string","description":"When the DNS records were last checked; null if never.","format":"date-time","nullable":true},"dns_zone":{"type":"string","nullable":true,"format":"hostname","description":"Zone apex found by walking SOA records up from the fqdn; null before the first check.","example":"example.com"},"ses_dkim_status":{"nullable":true,"description":"DKIM signing verification of this domain, mirrored on every check. `not_enabled` where sending verification is off in this environment (local, preview); null while the domain is not registered for signing yet.","allOf":[{"$ref":"#/components/schemas/SesDkimStatus"}]},"mail_from_subdomain":{"type":"string","nullable":true,"description":"Custom MAIL FROM label (`bounce` → `bounce.<fqdn>`); null when off. On by default for sending domains created since 2026-10.","example":"bounce"},"mail_from_status":{"nullable":true,"description":"Verification of the custom MAIL FROM host (its MX record); null when no custom MAIL FROM is configured.","allOf":[{"$ref":"#/components/schemas/SesMailFromStatus"}]},"dmarc_managed":{"type":"boolean","description":"false when the customer opted out of our `_dmarc` recommendation (PATCH `dmarc_managed`).","example":true},"setup_method":{"nullable":true,"description":"How the DNS records were last set up by an automated path: `provider_api` after `POST .../dns-records/apply` wrote them with a provider token, `domain_connect` after a Domain Connect flow. Null when the records were (or are being) added by hand.","example":null,"allOf":[{"$ref":"#/components/schemas/DomainSetupMethod"}]},"dmarc_grade":{"nullable":true,"description":"The DMARC policy that governs this domain, graded on the last check; null before the first check of a sending domain.","allOf":[{"$ref":"#/components/schemas/DmarcGradeDto"}]},"verified_at":{"type":"string","description":"When the domain was first verified; null until then.","format":"date-time","nullable":true},"created_at":{"type":"string","description":"When the domain was added.","format":"date-time"},"dns_instructions":{"description":"DNS records to publish for this domain's intent. Records with `required: true` gate `active`; the rest are informational.","type":"array","items":{"$ref":"#/components/schemas/DnsInstructionDto"}},"records":{"description":"The same records in Resend's `records[]` shape, each with its status.","type":"array","items":{"$ref":"#/components/schemas/DomainRecordDto"}},"test_address":{"type":"string","description":"Convenience accessor for the test-email mailbox address on this domain.","example":"test-abc123@productcraft.co"},"events":{"description":"The latest 20 domain events, newest first. Page through all of them with `GET .../domains/{id}/events`.","type":"array","items":{"$ref":"#/components/schemas/DomainEventDto"}}},"required":["id","seq_id","workspace_id","owner_account_id","fqdn","name","intent","capabilities","tls","open_tracking","click_tracking","tracking_subdomain","status","health","health_changed_at","health_grace_ends_at","verification_token","test_token","test_received_at","dkim_selector","dkim_public_key","dns_provider","dns_provider_id","dns_provider_detected","verification_status","recommended_pending","region","region_name","dns_check_results","last_dns_check_at","dns_zone","ses_dkim_status","mail_from_subdomain","mail_from_status","dmarc_managed","setup_method","dmarc_grade","verified_at","created_at","dns_instructions","records","test_address","events"],"x-pc-sdk-model":"DomainDetail"},"ListDomainEventsResponseDto":{"type":"object","properties":{"data":{"description":"The events on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/DomainEventDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListDomainEvents"},"UpdateDomainDto":{"type":"object","properties":{"tls":{"type":"string","enum":["opportunistic","enforced"],"default":"opportunistic","description":"`opportunistic` only for now (TLS whenever the receiver offers it); `enforced` is refused with 422 `TLS_ENFORCED_NOT_AVAILABLE`."},"open_tracking":{"type":"boolean","description":"Only `false` for now; `true` is refused with 422 `TRACKING_NOT_AVAILABLE`.","example":false},"click_tracking":{"type":"boolean","description":"Only `false` for now; `true` is refused with 422 `TRACKING_NOT_AVAILABLE`.","example":false},"tracking_subdomain":{"type":"string","description":"Not available yet: any value is refused with 422 `TRACKING_NOT_AVAILABLE`.","maxLength":63},"intent":{"type":"string","enum":["receive","send","both"],"description":"Change how the domain is used. On a verified domain, a capability it gains must verify first: its records are checked live and the change is refused with 409 `CAPABILITY_NOT_VERIFIED` (records to publish in `details.records`) until they pass. Dropping receiving is refused with 409 `DOMAIN_HAS_MAILBOXES` while active mailboxes exist (listed in `details.mailboxes`). Same as `capabilities`; send one or the other, or both in agreement."},"capabilities":{"description":"Resend's shape of `intent`. Omitted fields keep their current value; at least one must stay enabled.","allOf":[{"$ref":"#/components/schemas/DomainCapabilitiesInputDto"}]},"dns_provider":{"type":"string","description":"Identifier from the wizard's provider list. Free-form so we can ship new entries without a migration. NULL clears the choice.","nullable":true},"mail_from_subdomain":{"type":"string","description":"Custom MAIL FROM label: one DNS label, so `bounce` makes the envelope sender `…@bounce.<fqdn>` and SPF align with the From domain. `null` turns the custom MAIL FROM off (the default return address is used; DKIM still aligns). Sending domains only.","nullable":true,"example":"bounce","maxLength":63},"dmarc_managed":{"type":"boolean","description":"false: do not recommend a `_dmarc` record for this domain (DMARC is managed elsewhere). The policy that applies is still detected and graded in `dmarc_grade`.","example":false}}},"DnsRecordState":{"type":"string","enum":["missing","mismatch","conflict","propagating","verified"]},"DnsConflictCode":{"type":"string","enum":["spf_multiple","spf_merge","spf_lookup_limit","cname_at_host","mail_from_mx_multiple","dmarc_duplicate","dkim_selector_taken","mx_foreign"]},"DnsConflictSeverity":{"type":"string","enum":["blocking","warning"]},"DnsRecordConflictDto":{"type":"object","properties":{"code":{"description":"`spf_multiple`: more than one SPF record at the name (permerror). `spf_merge`: an SPF record exists, merge ours into it. `spf_lookup_limit`: the merged SPF needs more than 10 DNS lookups. `cname_at_host`: a CNAME occupies the name. `mail_from_mx_multiple`: the MAIL FROM host has other MX records. `dmarc_duplicate`: two DMARC records. `dkim_selector_taken`: a different DKIM key at our selector. `mx_foreign`: inbound mail for the name currently goes elsewhere (informational).","example":"spf_multiple","allOf":[{"$ref":"#/components/schemas/DnsConflictCode"}]},"severity":{"description":"`blocking`: the record cannot work until this is fixed. `warning`: works, but read this.","allOf":[{"$ref":"#/components/schemas/DnsConflictSeverity"}]},"message":{"type":"string","description":"One sentence on what is wrong and how to fix it."},"suggested_value":{"type":"string","description":"The value to publish instead (e.g. a merged SPF record), when there is one.","example":"v=spf1 include:amazonses.com include:_spf.google.com ~all"}},"required":["code","severity","message"],"x-pc-sdk-model":"DnsRecordConflict"},"DnsRecordStatusDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","nullable":true,"description":"Stored record id; null until the record has been checked once."},"purpose":{"description":"`dkim` signing key (also the ownership proof for sending domains); `mx` inbound routing; `verification` ownership token (receive-only); `spf` legacy From-domain SPF; `mail_from_mx` / `mail_from_spf` custom MAIL FROM; `dmarc` policy.","example":"dkim","allOf":[{"$ref":"#/components/schemas/DnsRecordPurpose"}]},"type":{"description":"DNS record type.","example":"TXT","allOf":[{"$ref":"#/components/schemas/DnsRecordType"}]},"host":{"type":"string","description":"Fully qualified name to publish at (no trailing dot).","example":"productcraft._domainkey.mail.example.com"},"name_relative":{"type":"string","description":"Name relative to the zone (`@` for the apex), the form most DNS provider UIs ask for.","example":"productcraft._domainkey.mail"},"value":{"type":"string","description":"Value to publish. For MX, the mail exchanger host (priority is separate).","example":"v=DKIM1; k=rsa; p=MIIBIjANBgkqh…"},"priority":{"type":"integer","nullable":true,"description":"MX preference; null for TXT.","example":10},"ttl":{"type":"integer","description":"TTL (seconds) we recommend publishing with.","example":3600},"required":{"type":"boolean","description":"Whether this record gates the domain going `active`.","example":true},"state":{"description":"`missing`: not published. `mismatch`: something else is published at that name (see `found`). `conflict`: published, but another record breaks it (see `conflicts`). `propagating`: your nameservers serve it, public resolvers do not yet (see `hint`). `verified`: published and visible.","example":"verified","allOf":[{"$ref":"#/components/schemas/DnsRecordState"}]},"found":{"description":"Values found at the name for this type, from the authoritative nameservers when reachable (TXT strings joined; MX as `<priority> <host>`).","type":"array","items":{"type":"string"}},"conflicts":{"description":"Conflicts detected on this record.","type":"array","items":{"$ref":"#/components/schemas/DnsRecordConflictDto"}},"hint":{"type":"string","nullable":true,"description":"One human sentence about the current state, including propagation timing.","example":"Your nameservers already serve it; public resolvers will within ~30 min (the zone's negative-cache TTL is 1800 s)."},"covered_by":{"type":"string","nullable":true,"description":"DMARC only: when no record is published at `host` and a parent domain's policy applies, the name that policy lives at. There is nothing to publish then: a record at `host` would replace the inherited policy. Null otherwise.","example":"_dmarc.example.com"},"first_verified_at":{"type":"string","format":"date-time","nullable":true,"description":"First time this exact record verified."},"last_checked_at":{"type":"string","description":"When this record was last checked; null if never.","format":"date-time","nullable":true},"last_changed_at":{"type":"string","format":"date-time","nullable":true,"description":"Last time the state (or the record) changed, or the nameservers stopped serving a published record (a hold: the state stays published for a few minutes while we re-check)."}},"required":["id","purpose","type","host","name_relative","value","priority","ttl","required","state","found","conflicts","hint","covered_by","first_verified_at","last_checked_at","last_changed_at"],"x-pc-sdk-model":"DnsRecordStatus"},"DomainSesStatusDto":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether sending verification (DKIM signing) is switched on for this deployment."},"dkim_status":{"nullable":true,"description":"DKIM signing verification of the DKIM record. `not_enabled` where sending verification is off in this environment (local, preview); null while the domain is not registered for signing yet.","allOf":[{"$ref":"#/components/schemas/SesDkimStatus"}]},"mail_from_status":{"nullable":true,"description":"Verification of the custom MAIL FROM host; null when none is configured.","allOf":[{"$ref":"#/components/schemas/SesMailFromStatus"}]}},"required":["enabled","dkim_status","mail_from_status"],"x-pc-sdk-model":"DomainSesStatus"},"DomainDnsRecordsDto":{"type":"object","properties":{"domain_id":{"type":"string","description":"The domain id.","format":"uuid"},"fqdn":{"type":"string","description":"The domain name.","example":"mail.example.com"},"status":{"description":"Verification status of the domain.","allOf":[{"$ref":"#/components/schemas/DomainStatus"}]},"health":{"example":"ok","description":"Drift on a verified domain. `degraded`: a required record (DKIM, or MX for receiving) went missing or changed, or DKIM signing no longer verifies; mail still flows and workspace owners are emailed. `failing`: still degraded 72 h later; sends from the domain are refused with 422 `domain_not_verified_by_provider`. Back to `ok` as soon as the records are. A failed DNS lookup never changes it, and recommended records (MAIL FROM, DMARC) never do. Always `ok` while the domain is not `active`.","allOf":[{"$ref":"#/components/schemas/DomainHealth"}]},"health_changed_at":{"type":"string","format":"date-time","nullable":true,"description":"When `health` last changed; null if it has always been `ok`."},"health_grace_ends_at":{"type":"string","format":"date-time","nullable":true,"description":"While `health` is `degraded`: when the 72 h grace ends and the domain becomes `failing` unless the records are back. Null otherwise."},"zone":{"type":"string","nullable":true,"description":"Zone the relative names are rendered against: the `zone` query parameter, else the zone found by walking SOA records (null before the first check).","example":"example.com"},"last_checked_at":{"type":"string","description":"When the records were last checked; null if never.","format":"date-time","nullable":true},"records":{"description":"Each required and recommended record with its current state.","type":"array","items":{"$ref":"#/components/schemas/DnsRecordStatusDto"}},"ses":{"$ref":"#/components/schemas/DomainSesStatusDto"}},"required":["domain_id","fqdn","status","health","health_changed_at","health_grace_ends_at","zone","last_checked_at","records","ses"],"x-pc-sdk-model":"DomainDnsRecords"},"CreateShareLinkDto":{"type":"object","properties":{"expires_in_days":{"type":"integer","minimum":1,"maximum":7,"default":7,"description":"Days until the link stops working (1–7).","example":7},"email_to":{"maxItems":5,"description":"Optional: email the link to these people (whoever manages the DNS). At most 5 recipients per domain per UTC day and 20 per workspace, counted across all links; over that the request is refused with 429 and no link is created. Each recipient gets their own email from ProductCraft with the domain name, the link and its expiry.","example":["it@example.com"],"type":"array","items":{"type":"string","format":"email"}}}},"ShareLinkStatus":{"type":"string","enum":["active","expired","revoked"]},"CreatedShareLinkDto":{"type":"object","properties":{"id":{"type":"string","description":"The share link id.","format":"uuid"},"domain_id":{"type":"string","description":"The domain the link shares the DNS setup of.","format":"uuid"},"status":{"description":"`active` until `expires_at` or until revoked.","example":"active","allOf":[{"$ref":"#/components/schemas/ShareLinkStatus"}]},"created_by":{"type":"string","nullable":true,"description":"Principal (`sub`) that created the link."},"created_at":{"type":"string","description":"When the link was created.","format":"date-time"},"expires_at":{"type":"string","description":"When the link stops working.","format":"date-time"},"revoked_at":{"type":"string","description":"When the link was revoked; null while not revoked.","format":"date-time","nullable":true},"last_viewed_at":{"type":"string","format":"date-time","nullable":true,"description":"Last time the public page was opened (updated at most once a minute)."},"emailed_to_count":{"type":"integer","description":"How many recipients the link was emailed to.","example":1},"url":{"type":"string","format":"uri","description":"The page to send: a read-only setup page with the records, live status and downloads, no account needed. Shown only in this response; it cannot be retrieved again (only a hash is stored). When the request carried an `Idempotency-Key`, a retry with the same key within 24 h returns this same response.","example":"https://console.productcraft.co/mail/setup/3q2-7wVdZ6xYb9mJk1Lr0pQs4tUv8wXyZaBcDeFgHiJ"},"api_url":{"type":"string","format":"uri","description":"The same link as JSON (`GET /v1/public/domain-setup/{token}`), for scripts.","example":"https://api.mail.productcraft.co/v1/public/domain-setup/3q2-7wVdZ6xYb9mJk1Lr0pQs4tUv8wXyZaBcDeFgHiJ"},"emailed_to":{"description":"Recipients the email was queued for (an address whose email could not be queued is left out).","example":["it@example.com"],"type":"array","items":{"type":"string","format":"email"}}},"required":["id","domain_id","status","created_by","created_at","expires_at","revoked_at","last_viewed_at","emailed_to_count","url","api_url","emailed_to"],"x-pc-sdk-model":"CreatedShareLink"},"ShareLinkDto":{"type":"object","properties":{"id":{"type":"string","description":"The share link id.","format":"uuid"},"domain_id":{"type":"string","description":"The domain the link shares the DNS setup of.","format":"uuid"},"status":{"description":"`active` until `expires_at` or until revoked.","example":"active","allOf":[{"$ref":"#/components/schemas/ShareLinkStatus"}]},"created_by":{"type":"string","nullable":true,"description":"Principal (`sub`) that created the link."},"created_at":{"type":"string","description":"When the link was created.","format":"date-time"},"expires_at":{"type":"string","description":"When the link stops working.","format":"date-time"},"revoked_at":{"type":"string","description":"When the link was revoked; null while not revoked.","format":"date-time","nullable":true},"last_viewed_at":{"type":"string","format":"date-time","nullable":true,"description":"Last time the public page was opened (updated at most once a minute)."},"emailed_to_count":{"type":"integer","description":"How many recipients the link was emailed to.","example":1}},"required":["id","domain_id","status","created_by","created_at","expires_at","revoked_at","last_viewed_at","emailed_to_count"],"x-pc-sdk-model":"ShareLink"},"ListShareLinksResponseDto":{"type":"object","properties":{"data":{"description":"The share links on this page.","type":"array","items":{"$ref":"#/components/schemas/ShareLinkDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListShareLinks"},"PublicDnsRecordDto":{"type":"object","properties":{"purpose":{"description":"What the record is for.","example":"dkim","allOf":[{"$ref":"#/components/schemas/DnsRecordPurpose"}]},"type":{"description":"DNS record type.","example":"TXT","allOf":[{"$ref":"#/components/schemas/DnsRecordType"}]},"host":{"type":"string","description":"Fully qualified name (no trailing dot).","example":"productcraft._domainkey.mail.example.com"},"name_relative":{"type":"string","description":"Name relative to the zone (`@` for the apex).","example":"productcraft._domainkey.mail"},"value":{"type":"string","description":"The value to publish.","example":"v=DKIM1; k=rsa; p=MIIBIjANBgkqh…"},"priority":{"type":"integer","description":"MX priority; null for TXT records.","nullable":true,"example":10},"ttl":{"type":"integer","description":"Suggested TTL in seconds.","example":3600},"required":{"type":"boolean","description":"Whether the domain needs this record to start sending.","example":true},"state":{"description":"What the last check found: `missing`, `mismatch` (a different value is published), `conflict` (another record at the host clashes), `propagating` or `verified`.","example":"missing","allOf":[{"$ref":"#/components/schemas/DnsRecordState"}]},"found":{"description":"What public DNS currently serves at that name for this type.","type":"array","items":{"type":"string"}},"conflicts":{"description":"Existing records at the same host that conflict with this one.","type":"array","items":{"$ref":"#/components/schemas/DnsRecordConflictDto"}},"hint":{"type":"string","nullable":true,"description":"One sentence about the current state."},"covered_by":{"type":"string","nullable":true,"description":"DMARC only: the parent-domain policy name that applies while nothing is published at `host`; nothing to add then. Null otherwise.","example":"_dmarc.example.com"},"last_checked_at":{"type":"string","description":"When this record was last checked; null if never.","format":"date-time","nullable":true}},"required":["purpose","type","host","name_relative","value","priority","ttl","required","state","found","conflicts","hint","covered_by","last_checked_at"]},"PublicSesStatusDto":{"type":"object","properties":{"dkim_status":{"nullable":true,"description":"DKIM signing verification of the DKIM record.","allOf":[{"$ref":"#/components/schemas/SesDkimStatus"}]},"mail_from_status":{"nullable":true,"description":"Verification of the custom MAIL FROM host.","allOf":[{"$ref":"#/components/schemas/SesMailFromStatus"}]}},"required":["dkim_status","mail_from_status"]},"PublicSetupExportsDto":{"type":"object","properties":{"bind":{"type":"string","format":"uri","description":"BIND zone fragment of the records still to publish."},"csv":{"type":"string","format":"uri","description":"CSV of the records still to publish."}},"required":["bind","csv"]},"PublicDomainSetupDto":{"type":"object","properties":{"fqdn":{"type":"string","description":"The domain name.","example":"mail.example.com"},"status":{"description":"`active` once the required records verify.","allOf":[{"$ref":"#/components/schemas/DomainStatus"}]},"zone":{"type":"string","nullable":true,"example":"example.com","description":"Zone the relative names are rendered against."},"last_checked_at":{"type":"string","format":"date-time","nullable":true,"description":"When the records were last checked (every 5 minutes while the domain is pending, hourly once active)."},"expires_at":{"type":"string","format":"date-time","description":"When this link stops working."},"records":{"description":"The records to publish.","type":"array","items":{"$ref":"#/components/schemas/PublicDnsRecordDto"}},"ses":{"$ref":"#/components/schemas/PublicSesStatusDto"},"exports":{"$ref":"#/components/schemas/PublicSetupExportsDto"}},"required":["fqdn","status","zone","last_checked_at","expires_at","records","ses","exports"]},"ApplyDnsRecordsDto":{"type":"object","properties":{"provider":{"type":"string","enum":["cloudflare","digitalocean"],"description":"The DNS provider that hosts the zone.","example":"cloudflare"},"token":{"type":"string","writeOnly":true,"format":"password","minLength":20,"maxLength":512,"description":"A short-lived API token for the provider, used for this request only and never stored, logged or returned. Cloudflare: an API token limited to this one zone with the **Zone → DNS → Edit** permission and a short expiry. DigitalOcean: a personal access token with custom scopes `domain:read`, `domain:create`, `domain:update` and a 1-hour expiry. Revoke it once the apply is done.","example":"dop_v1_EXAMPLE_TOKEN_DO_NOT_USE"},"zone":{"type":"string","format":"hostname","description":"The zone at the provider (the domain or one of its parents). Defaults to the closest parent zone the token can see.","example":"example.com"},"dry_run":{"type":"boolean","description":"`true`: return the plan and change nothing. `false`: apply the plan and return what was written.","example":true},"include_dmarc":{"type":"boolean","default":true,"description":"Also add the recommended DMARC record (`_dmarc.<fqdn>` `v=DMARC1; p=none;`). Only ever planned when no DMARC policy applies at the domain or its organisational domain; an existing policy is never touched, whatever this says.","example":true}},"required":["provider","token","dry_run"]},"DnsApplyProvider":{"type":"string","enum":["cloudflare","digitalocean"]},"DnsApplyAction":{"type":"string","enum":["create","update","skip"]},"DnsApplyRecordResult":{"type":"string","enum":["created","updated","unchanged","failed"]},"DnsApplyPlanItemDto":{"type":"object","properties":{"action":{"description":"`create`: a new record is added. `update`: an existing SPF record absorbs our mechanism (the only record we ever modify; see `before`/`after`). `skip`: already in place, or nothing to do (see `note`).","example":"create","allOf":[{"$ref":"#/components/schemas/DnsApplyAction"}]},"purpose":{"description":"What the record is for (`dkim`, `mx`, `verification`, `spf`, `mail_from_mx`, `mail_from_spf`, `dmarc`).","example":"dkim","allOf":[{"$ref":"#/components/schemas/DnsRecordPurpose"}]},"type":{"description":"DNS record type.","example":"TXT","allOf":[{"$ref":"#/components/schemas/DnsRecordType"}]},"host":{"type":"string","description":"Fully qualified name (no trailing dot).","example":"productcraft._domainkey.mail.example.com"},"name_relative":{"type":"string","description":"Name relative to the provider zone (`@` for the apex).","example":"productcraft._domainkey.mail"},"value":{"type":"string","description":"The value written (an update: the merged record). For MX, the mail exchanger host; the priority is separate.","example":"v=DKIM1; k=rsa; p=MIIBIjANBgkqh…"},"priority":{"type":"integer","nullable":true,"description":"MX preference; null for TXT.","example":null},"ttl":{"type":"integer","description":"TTL (seconds) the record is written with.","example":3600},"required":{"type":"boolean","description":"Whether this record gates the domain going `active`.","example":true},"optional":{"type":"boolean","description":"A recommended extra the caller opted into (`include_dmarc`).","example":false},"existing":{"description":"What the zone holds today at `host` for this record type (TXT unquoted and joined; MX as `<priority> <host>`).","type":"array","items":{"type":"string"}},"before":{"type":"string","nullable":true,"description":"`update`: the record being replaced. `skip`: the record already satisfying ours. Null for `create`.","example":null},"after":{"type":"string","nullable":true,"description":"The record after the apply (MX as `<priority> <host>`). For `skip`, the same as `before`.","example":"v=DKIM1; k=rsa; p=MIIBIjANBgkqh…"},"note":{"type":"string","nullable":true,"description":"Why a record is skipped, when it is not simply already in place.","example":null},"conflicts":{"description":"Conflicts on this record. Any `blocking` one refuses the apply (409).","type":"array","items":{"$ref":"#/components/schemas/DnsRecordConflictDto"}},"result":{"nullable":true,"description":"What happened to this record on an apply; null on a dry run.","example":"created","allOf":[{"$ref":"#/components/schemas/DnsApplyRecordResult"}]},"error":{"type":"string","nullable":true,"description":"Why the write failed (`result: failed`).","example":null}},"required":["action","purpose","type","host","name_relative","value","priority","ttl","required","optional","existing","before","after","note","conflicts","result","error"],"x-pc-sdk-model":"DnsApplyPlanItem"},"DnsApplyConflictDto":{"type":"object","properties":{"code":{"description":"`spf_multiple`: more than one SPF record at the name (permerror). `spf_merge`: an SPF record exists, merge ours into it. `spf_lookup_limit`: the merged SPF needs more than 10 DNS lookups. `cname_at_host`: a CNAME occupies the name. `mail_from_mx_multiple`: the MAIL FROM host has other MX records. `dmarc_duplicate`: two DMARC records. `dkim_selector_taken`: a different DKIM key at our selector. `mx_foreign`: inbound mail for the name currently goes elsewhere (informational).","example":"spf_multiple","allOf":[{"$ref":"#/components/schemas/DnsConflictCode"}]},"severity":{"description":"`blocking`: the record cannot work until this is fixed. `warning`: works, but read this.","allOf":[{"$ref":"#/components/schemas/DnsConflictSeverity"}]},"message":{"type":"string","description":"One sentence on what is wrong and how to fix it."},"suggested_value":{"type":"string","description":"The value to publish instead (e.g. a merged SPF record), when there is one.","example":"v=spf1 include:amazonses.com include:_spf.google.com ~all"},"purpose":{"description":"What the conflicting record is for.","example":"mail_from_mx","allOf":[{"$ref":"#/components/schemas/DnsRecordPurpose"}]},"host":{"type":"string","description":"Host name of the record.","example":"bounce.mail.example.com"}},"required":["code","severity","message","purpose","host"],"x-pc-sdk-model":"DnsApplyConflict"},"DnsApplyCountsDto":{"type":"object","properties":{"create":{"type":"integer","description":"Records that would be (or were) created.","example":4},"update":{"type":"integer","description":"Records that would be (or were) updated.","example":0},"skip":{"type":"integer","description":"Records already correct and left as they are.","example":0},"failed":{"type":"integer","description":"Writes that failed (apply only).","example":0}},"required":["create","update","skip","failed"],"x-pc-sdk-model":"DnsApplyCounts"},"DnsApplyWarning":{"type":"string","enum":["token_scope_broader_than_zone","dmarc_lookup_failed","partially_applied"]},"DnsApplyResultDto":{"type":"object","properties":{"domain_id":{"type":"string","description":"The domain the records were applied to.","format":"uuid"},"fqdn":{"type":"string","description":"The domain name.","format":"hostname","example":"mail.example.com"},"provider":{"description":"The DNS provider the records were written to.","example":"cloudflare","allOf":[{"$ref":"#/components/schemas/DnsApplyProvider"}]},"zone":{"type":"string","format":"hostname","description":"The provider zone the records go into.","example":"example.com"},"dry_run":{"type":"boolean","description":"True when this was a dry run: nothing was written.","example":true},"applied":{"type":"boolean","description":"Whether records were written (false on a dry run).","example":false},"plan":{"description":"Each record and what was (or would be) done with it.","type":"array","items":{"$ref":"#/components/schemas/DnsApplyPlanItemDto"}},"conflicts":{"description":"Every conflict in the plan, flattened, with the record it belongs to.","type":"array","items":{"$ref":"#/components/schemas/DnsApplyConflictDto"}},"counts":{"$ref":"#/components/schemas/DnsApplyCountsDto"},"warnings":{"type":"array","description":"`token_scope_broader_than_zone`: the token can see more than this zone; it worked, but revoke it now. `dmarc_lookup_failed`: we could not tell whether a DMARC policy applies, so DMARC was left out. `partially_applied`: some writes failed (see each item's `error`); run it again once fixed, finished records are skipped.","example":["token_scope_broader_than_zone"],"items":{"$ref":"#/components/schemas/DnsApplyWarning"}},"dmarc_available":{"type":"boolean","description":"No DMARC policy applies to this domain, so the optional DMARC record can be added (`include_dmarc`).","example":true},"dns_records":{"nullable":true,"description":"After an apply: the result of the DNS check run right away (new records are usually `propagating`). Null on a dry run.","allOf":[{"$ref":"#/components/schemas/DomainDnsRecordsDto"}]}},"required":["domain_id","fqdn","provider","zone","dry_run","applied","plan","conflicts","counts","warnings","dmarc_available","dns_records"],"x-pc-sdk-model":"DnsApplyResult"},"StartDomainConnectDto":{"type":"object","properties":{"include_dmarc":{"type":"boolean","default":true,"description":"Also add the recommended DMARC record (`v=DMARC1; p=none;` at `_dmarc.<domain>`) as a second confirmation at the provider. Ignored, and not offered, when a DMARC policy already applies to the domain or its organisational domain, when DMARC is not managed here (`dmarc_managed: false`), or when the provider has not onboarded the DMARC template.","example":true}}},"DomainConnectStartDto":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"The signed Domain Connect apply URL at the DNS provider. Open it in the user's browser (a top-level navigation, not a fetch): the provider asks them to sign in and confirm, writes the records, and sends them back to ProductCraft, which checks the records and returns them to the domain's page in the console. Valid for 10 minutes and usable once.","example":"https://dash.cloudflare.com/domainconnect/v2/domainTemplates/providers/productcraft.co/services/mail/apply?domain=example.com&host=mail&dkimkey=MIIBIjANBg...&redirect_uri=https%3A%2F%2Fapi.mail.productcraft.co%2Fv1%2Fdomain-connect%2Fcallback&state=3q2-7wVdZ6xYb9mJk1Lr0pQs4tUv8wXy&key=_dck1&sig=Qm9n..."},"provider_name":{"type":"string","example":"Cloudflare","description":"The DNS provider the URL goes to, for the button label."},"zone":{"type":"string","example":"example.com","format":"hostname","description":"The zone the records are written into."},"includes_dmarc":{"type":"boolean","description":"A second confirmation for the DMARC record follows the first one at the provider.","example":true},"expires_at":{"type":"string","format":"date-time","description":"When the URL stops working (10 minutes)."}},"required":["url","provider_name","zone","includes_dmarc","expires_at"],"x-pc-sdk-model":"DomainConnectStart"},"OutboundWebhookConfigDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"Null for the workspace-default config; set for a per-domain override."},"url":{"type":"string","format":"uri"},"event_types":{"type":"array","items":{"type":"string"}},"signing_secret_hint":{"type":"string","description":"Last 4 chars of the active signing secret."},"prev_signing_secret_active":{"type":"boolean","description":"True while a previous signing secret is still being honoured (24h grace after rotation)."},"prev_signing_secret_expires_at":{"type":"string","format":"date-time","nullable":true},"disabled_at":{"type":"string","format":"date-time","nullable":true,"description":"Set when auto-disabled after sustained failure."},"disabled_reason":{"type":"string","nullable":true},"consecutive_failures":{"type":"number"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","workspace_id","domain_id","url","event_types","signing_secret_hint","prev_signing_secret_active","prev_signing_secret_expires_at","disabled_at","disabled_reason","consecutive_failures","created_at","updated_at"]},"UpsertOutboundWebhookDto":{"type":"object","properties":{"url":{"type":"string","description":"Destination URL. Must be absolute https:// with a public TLD.","format":"uri","example":"https://api.acme.com/webhooks/mail","maxLength":2048},"event_types":{"type":"array","description":"Events the destination subscribes to: any name of the catalogue (`email.*`, `domain.*`, `suppression.*`; see `/webhooks/endpoints`), or a pre-042 `message.*` alias (`message.sent|delivered|deferred|bounced|complained|failed`, kept for one release), which is delivered under the alias name. Email events carry the message; `domain.*` events carry `data: { id, fqdn, status, health }`, where `health` is `ok | degraded | failing` (drift on a verified domain; `failing` = still broken 72 h later, sends refused). `domain.created` adds `intent` and `created_at`; `domain.verified` adds `verified_at`; `domain.updated` adds `changes: [{ purpose, from, to }]` (a record purpose such as `dkim`, `mx`, `mail_from_mx`, `dmarc` with its state `missing | mismatch | conflict | propagating | verified`, or `ses` / `ses_mail_from` with the signing / MAIL FROM check status) and fires only on a real change; `domain.deleted` is sent after the domain is removed.","example":["email.sent","email.bounced"],"items":{"type":"string","enum":["email.sent","email.delivered","email.delivery_delayed","email.bounced","email.complained","email.failed","email.suppressed","email.skipped","email.scheduled","email.canceled","email.opened","email.clicked","email.received","domain.created","domain.updated","domain.verified","domain.deleted","suppression.added","suppression.removed","sending_defaults.updated","contact.created","contact.updated","contact.deleted","message.sent","message.delivered","message.deferred","message.bounced","message.complained","message.failed"]}}},"required":["url","event_types"]},"OutboundWebhookConfigWithSecretDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"Null for the workspace-default config; set for a per-domain override."},"url":{"type":"string","format":"uri"},"event_types":{"type":"array","items":{"type":"string"}},"signing_secret_hint":{"type":"string","description":"Last 4 chars of the active signing secret."},"prev_signing_secret_active":{"type":"boolean","description":"True while a previous signing secret is still being honoured (24h grace after rotation)."},"prev_signing_secret_expires_at":{"type":"string","format":"date-time","nullable":true},"disabled_at":{"type":"string","format":"date-time","nullable":true,"description":"Set when auto-disabled after sustained failure."},"disabled_reason":{"type":"string","nullable":true},"consecutive_failures":{"type":"number"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"signing_secret":{"type":"string","description":"Plaintext signing secret. Returned once on create / rotate; never reconstructable."}},"required":["id","workspace_id","domain_id","url","event_types","signing_secret_hint","prev_signing_secret_active","prev_signing_secret_expires_at","disabled_at","disabled_reason","consecutive_failures","created_at","updated_at","signing_secret"]},"OutboundWebhookAttemptDto":{"type":"object","properties":{"id":{"type":"string","description":"The attempt id.","format":"uuid"},"event_id":{"type":"string","description":"The logged event (`GET /webhooks/events/{id}`).","pattern":"^evt_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},"event_type":{"type":"string","description":"The `type` the endpoint received (a legacy alias for an endpoint subscribed under one).","example":"email.bounced"},"attempt_number":{"type":"number","description":"1 for the first delivery; a replay adds the next number."},"status_code":{"type":"number","description":"HTTP status the endpoint answered; null when the request got no response.","nullable":true},"error_message":{"type":"string","description":"Why the attempt failed; null when it succeeded.","nullable":true},"response_body_truncated":{"type":"string","nullable":true,"description":"The receiver's response body, truncated to 1KB by the dispatcher. Null when the request never got a response (DNS / connect / timeout) — read `error_message` in that case."},"latency_ms":{"type":"number","description":"How long the request took in milliseconds; null when it got no response.","nullable":true},"attempted_at":{"type":"string","description":"When the attempt was made.","format":"date-time"},"url":{"type":"string","description":"The URL the attempt was sent to.","format":"uri"},"domain_id":{"type":"string","description":"Legacy per-domain endpoint the attempt went to; null otherwise.","format":"uuid","nullable":true},"endpoint_id":{"type":"string","format":"uuid","description":"The endpoint the attempt was made to."}},"required":["id","event_id","event_type","attempt_number","status_code","error_message","response_body_truncated","latency_ms","attempted_at","url","domain_id","endpoint_id"],"x-pc-sdk-model":"OutboundWebhookAttempt"},"ListWebhookAttemptsResponseDto":{"type":"object","properties":{"data":{"description":"Attempts, newest first.","type":"array","items":{"$ref":"#/components/schemas/OutboundWebhookAttemptDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListWebhookAttempts"},"EmailSentEventDataDto":{"type":"object","properties":{"from":{"type":"string","format":"email","example":"hello@acme.com","description":"The sender address."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient this event is about (one event per recipient)."},"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email (`GET /emails/{id}`), when the send stored one."},"message_id":{"type":"string","nullable":true,"example":"<0102019a1b2c3d4e-5f6a@email.amazonses.com>","description":"The Message-ID the relay or SES gave the message."},"smtp_response":{"type":"string","nullable":true,"example":"250 Ok","description":"What the next hop answered when it took the message."},"sent_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:00.000Z","description":"When the message was handed off. This is acceptance by the relay or SES, not delivery to the inbox."},"transport":{"type":"string","nullable":true,"example":"ses","description":"How it was sent: `ses`, or `smtp` (your own SMTP server)."}},"required":["from","to","sent_at"],"x-pc-sdk-model":"EmailSentEventData"},"EmailDeliveredEventDataDto":{"type":"object","properties":{"from":{"type":"string","format":"email","example":"hello@acme.com","description":"The sender address."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient this event is about (one event per recipient)."},"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email (`GET /emails/{id}`). Present when the event can be tied to a stored email."},"message_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The per-recipient message (`GET /messages/{id}`). Sent on events reported by SES."},"source":{"type":"string","example":"ses","description":"Where the event came from: `ses`. Sent on events reported by SES."},"ses_event":{"type":"string","example":"Delivery","description":"The SES notification type (`Delivery`, `Bounce`, `DeliveryDelay`, `Complaint`, `Reject`, `RenderingFailure`). Sent on events reported by SES."},"event":{"type":"string","example":"Delivery","description":"Same as `ses_event`. Sent on events reported by SES."},"occurred_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:02.000Z","description":"When SES reports it happened. Sent on events reported by SES."},"reporting_mta":{"type":"string","example":"a1.fra1.example.net","description":"The MTA that reported the event. Sent on events reported by SES."},"smtp_response":{"type":"string","example":"250 2.0.0 OK","description":"What the receiving server answered."},"remote_mta":{"type":"string","example":"203.0.113.10","description":"The receiving server."},"processing_time_ms":{"type":"integer","example":1840,"description":"How long delivery took, in milliseconds."}},"required":["from","to"],"x-pc-sdk-model":"EmailDeliveredEventData"},"EmailDeliveryDelayedEventDataDto":{"type":"object","properties":{"from":{"type":"string","format":"email","example":"hello@acme.com","description":"The sender address."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient this event is about (one event per recipient)."},"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email (`GET /emails/{id}`). Present when the event can be tied to a stored email."},"message_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The per-recipient message (`GET /messages/{id}`). Sent on events reported by SES."},"source":{"type":"string","example":"ses","description":"Where the event came from: `ses`. Sent on events reported by SES."},"ses_event":{"type":"string","example":"Delivery","description":"The SES notification type (`Delivery`, `Bounce`, `DeliveryDelay`, `Complaint`, `Reject`, `RenderingFailure`). Sent on events reported by SES."},"event":{"type":"string","example":"Delivery","description":"Same as `ses_event`. Sent on events reported by SES."},"occurred_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:02.000Z","description":"When SES reports it happened. Sent on events reported by SES."},"reporting_mta":{"type":"string","example":"a1.fra1.example.net","description":"The MTA that reported the event. Sent on events reported by SES."},"smtp_code":{"type":"string","example":"4.7.0","description":"Enhanced SMTP status code of the deferral, when reported."},"smtp_response":{"type":"string","example":"421 4.7.0 Try again later","description":"The receiving server's answer. Relay path."},"diagnostic_code":{"type":"string","example":"smtp; 421 4.7.0 Try again later","description":"The diagnostic text. Sent on events reported by SES."},"delay_type":{"type":"string","example":"TransientCommunicationFailure","description":"Why SES is delaying (its `delayType`). Sent on events reported by SES."},"bounce_type":{"type":"string","example":"Transient","description":"Set when SES reported a transient bounce (`Transient`)."},"bounce_subtype":{"type":"string","example":"MailboxFull","description":"SES bounce subtype of a transient bounce."},"action":{"type":"string","example":"delayed","description":"The DSN action of a transient bounce."},"remote_mta":{"type":"string","example":"203.0.113.10","description":"The server that deferred the message, on a transient bounce."},"feedback_id":{"type":"string","example":"0102019a1b2c3d4e-feedback","description":"SES feedback id of a transient bounce."},"retry_until":{"type":"string","format":"date-time","example":"2026-10-18T10:00:00.000Z","description":"When delivery attempts stop, when reported."},"deferred_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:02.000Z","description":"When the relay was told to retry. Relay path."}},"required":["from","to"],"x-pc-sdk-model":"EmailDeliveryDelayedEventData"},"EmailBouncedEventDataDto":{"type":"object","properties":{"from":{"type":"string","format":"email","example":"hello@acme.com","description":"The sender address."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient this event is about (one event per recipient)."},"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email (`GET /emails/{id}`). Present when the event can be tied to a stored email."},"message_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The per-recipient message (`GET /messages/{id}`). Sent on events reported by SES."},"source":{"type":"string","example":"ses","description":"Where the event came from: `ses`. Sent on events reported by SES."},"ses_event":{"type":"string","example":"Delivery","description":"The SES notification type (`Delivery`, `Bounce`, `DeliveryDelay`, `Complaint`, `Reject`, `RenderingFailure`). Sent on events reported by SES."},"event":{"type":"string","example":"Delivery","description":"Same as `ses_event`. Sent on events reported by SES."},"occurred_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:02.000Z","description":"When SES reports it happened. Sent on events reported by SES."},"reporting_mta":{"type":"string","example":"a1.fra1.example.net","description":"The MTA that reported the event. Sent on events reported by SES."},"smtp_code":{"type":"string","example":"5.1.1","description":"Enhanced SMTP status code of the bounce, when reported."},"smtp_response":{"type":"string","example":"550 5.1.1 user unknown","description":"The receiving server's answer. Relay path."},"bounced_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:02.000Z","description":"When the bounce arrived. Relay path."},"bounce_type":{"type":"string","example":"Permanent","description":"SES bounce type (`Permanent` or `Undetermined`). Sent on events reported by SES."},"bounce_subtype":{"type":"string","example":"General","description":"SES bounce subtype. Sent on events reported by SES."},"diagnostic_code":{"type":"string","example":"smtp; 550 5.1.1 user unknown","description":"The diagnostic text. Sent on events reported by SES."},"action":{"type":"string","example":"failed","description":"The DSN action. Sent on events reported by SES."},"remote_mta":{"type":"string","example":"203.0.113.10","description":"The server that refused the message. Sent on events reported by SES."},"feedback_id":{"type":"string","example":"0102019a1b2c3d4e-feedback","description":"SES feedback id. Sent on events reported by SES."}},"required":["from","to"],"x-pc-sdk-model":"EmailBouncedEventData"},"EmailComplainedEventDataDto":{"type":"object","properties":{"from":{"type":"string","format":"email","example":"hello@acme.com","description":"The sender address."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient this event is about (one event per recipient)."},"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email (`GET /emails/{id}`). Present when the event can be tied to a stored email."},"message_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The per-recipient message (`GET /messages/{id}`). Sent on events reported by SES."},"source":{"type":"string","example":"ses","description":"Where the event came from: `ses`. Sent on events reported by SES."},"ses_event":{"type":"string","example":"Delivery","description":"The SES notification type (`Delivery`, `Bounce`, `DeliveryDelay`, `Complaint`, `Reject`, `RenderingFailure`). Sent on events reported by SES."},"event":{"type":"string","example":"Delivery","description":"Same as `ses_event`. Sent on events reported by SES."},"occurred_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:02.000Z","description":"When SES reports it happened. Sent on events reported by SES."},"reporting_mta":{"type":"string","example":"a1.fra1.example.net","description":"The MTA that reported the event. Sent on events reported by SES."},"feedback_type":{"type":"string","example":"abuse","description":"The complaint feedback type (ARF), when reported."},"complaint_subtype":{"type":"string","example":"OnAccountSuppressionList","description":"SES complaint subtype, when reported."},"user_agent":{"type":"string","example":"Yahoo!-Mail-Feedback/2.0","description":"The reporting agent, when reported."},"feedback_id":{"type":"string","example":"0102019a1b2c3d4e-feedback","description":"SES feedback id."}},"required":["from","to"],"x-pc-sdk-model":"EmailComplainedEventData"},"EmailFailedEventDataDto":{"type":"object","properties":{"from":{"type":"string","format":"email","example":"hello@acme.com","description":"The sender address."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient this event is about (one event per recipient)."},"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email (`GET /emails/{id}`). Present when the event can be tied to a stored email."},"message_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The per-recipient message (`GET /messages/{id}`). Sent on events reported by SES."},"source":{"type":"string","example":"ses","description":"Where the event came from: `ses`. Sent on events reported by SES."},"ses_event":{"type":"string","example":"Delivery","description":"The SES notification type (`Delivery`, `Bounce`, `DeliveryDelay`, `Complaint`, `Reject`, `RenderingFailure`). Sent on events reported by SES."},"event":{"type":"string","example":"Delivery","description":"Same as `ses_event`. Sent on events reported by SES."},"occurred_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:02.000Z","description":"When SES reports it happened. Sent on events reported by SES."},"reporting_mta":{"type":"string","example":"a1.fra1.example.net","description":"The MTA that reported the event. Sent on events reported by SES."},"reason":{"type":"string","example":"The template could not be rendered","description":"Why the message was not sent."},"error":{"type":"string","nullable":true,"example":"RenderingFailure","description":"The error class, when the send itself failed."},"transport":{"type":"string","nullable":true,"example":"ses","description":"How it was being sent: `ses` or `smtp`."},"failed_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:01.000Z","description":"When the send failed (send-failure path)."},"template_name":{"type":"string","example":"welcome","description":"The SES template that failed to render. Sent on events reported by SES."}},"required":["from","to"],"x-pc-sdk-model":"EmailFailedEventData"},"EmailSuppressedEventDataDto":{"type":"object","properties":{"from":{"type":"string","format":"email","example":"hello@acme.com","description":"The sender address."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient this event is about (one event per recipient)."},"template":{"type":"string","example":"welcome","description":"The template of the refused send, when it was a template send."},"reason":{"type":"string","example":"suppressed","description":"Why it was refused: `suppressed` (on the suppression list), `unsubscribe` (opted out globally or of the topic) or `no_consent` (a topic send to someone who never opted in)."},"topic_id":{"type":"string","format":"uuid","description":"The topic of the send, when it had one."},"refused_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:00.000Z","description":"When the send was refused."}},"required":["from","to","reason","refused_at"],"x-pc-sdk-model":"EmailSuppressedEventData"},"EmailSkippedEventDataDto":{"type":"object","properties":{"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient of the skipped send."},"template":{"type":"string","example":"welcome","description":"The template of the skipped send."},"reason":{"type":"string","example":"no_default_sender","description":"Why it was skipped: `no_default_sender` (no `from` given and no workspace default sender)."},"skipped_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:00.000Z","description":"When the send was skipped."}},"required":["to","template","reason","skipped_at"],"x-pc-sdk-model":"EmailSkippedEventData"},"EmailScheduledEventDataDto":{"type":"object","properties":{"from":{"type":"string","format":"email","example":"hello@acme.com","description":"The sender address."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient this event is about (one event per recipient)."},"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email. Not sent yet: an endpoint can subscribe now and receives it when the feature ships."},"scheduled_at":{"type":"string","format":"date-time","example":"2026-10-18T09:00:00.000Z","description":"When the email will be sent."}},"required":["from","to","email_id","scheduled_at"],"x-pc-sdk-model":"EmailScheduledEventData"},"EmailCanceledEventDataDto":{"type":"object","properties":{"from":{"type":"string","format":"email","example":"hello@acme.com","description":"The sender address."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient this event is about (one event per recipient)."},"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email. Not sent yet: an endpoint can subscribe now and receives it when the feature ships."},"canceled_at":{"type":"string","format":"date-time","example":"2026-10-17T12:00:00.000Z","description":"When the scheduled email was canceled."}},"required":["from","to","email_id","canceled_at"],"x-pc-sdk-model":"EmailCanceledEventData"},"EmailOpenedEventDataDto":{"type":"object","properties":{"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email. Not sent yet: an endpoint can subscribe now and receives it when the feature ships."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient who opened it."},"opened_at":{"type":"string","format":"date-time","example":"2026-10-17T10:10:00.000Z","description":"When it was opened."}},"required":["email_id","to","opened_at"],"x-pc-sdk-model":"EmailOpenedEventData"},"EmailClickedEventDataDto":{"type":"object","properties":{"email_id":{"type":"string","format":"uuid","example":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","description":"The email. Not sent yet: an endpoint can subscribe now and receives it when the feature ships."},"to":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The recipient who clicked."},"link":{"type":"string","format":"uri","example":"https://acme.com/welcome","description":"The link that was clicked."},"clicked_at":{"type":"string","format":"date-time","example":"2026-10-17T10:11:00.000Z","description":"When it was clicked."}},"required":["email_id","to","link","clicked_at"],"x-pc-sdk-model":"EmailClickedEventData"},"EmailReceivedEventDataDto":{"type":"object","properties":{"from":{"type":"string","example":"customer@example.com","description":"The sender. Not sent yet: an endpoint can subscribe now and receives it when the feature ships."},"to":{"type":"string","example":"support@acme.com","description":"The address it was received on."},"subject":{"type":"string","nullable":true,"example":"Question about my order","description":"The subject line; null when it has none."},"received_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:00.000Z","description":"When it arrived."}},"required":["from","to","subject","received_at"],"x-pc-sdk-model":"EmailReceivedEventData"},"DomainCreatedEventDataDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","description":"The domain id."},"fqdn":{"type":"string","example":"acme.com","description":"The domain name."},"status":{"type":"string","example":"pending","description":"The domain status: `pending`, `active`, `disabled`, or `deleted` on `domain.deleted`."},"health":{"type":"string","example":"ok","description":"Drift on a verified domain: `ok`, `degraded` or `failing`."},"intent":{"type":"string","example":"send","description":"How the workspace uses the domain: `send`, `receive` or `both`."},"created_at":{"type":"string","format":"date-time","nullable":true,"example":"2026-10-17T09:00:00.000Z","description":"When the domain was added."}},"required":["id","fqdn","status","health","intent","created_at"],"x-pc-sdk-model":"DomainCreatedEventData"},"DomainRecordChangeDto":{"type":"object","properties":{"purpose":{"type":"string","example":"dkim","description":"What the record is for (`dkim`, `mx`, `spf`, `mail_from_mx`, `mail_from_spf`, `dmarc`, `verification`)."},"from":{"type":"string","nullable":true,"example":"propagating","description":"The record state before the check; null when it was not checked before."},"to":{"type":"string","example":"verified","description":"The record state after the check."}},"required":["purpose","from","to"],"x-pc-sdk-model":"DomainRecordChange"},"DomainUpdatedEventDataDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","description":"The domain id."},"fqdn":{"type":"string","example":"acme.com","description":"The domain name."},"status":{"type":"string","example":"pending","description":"The domain status: `pending`, `active`, `disabled`, or `deleted` on `domain.deleted`."},"health":{"type":"string","example":"ok","description":"Drift on a verified domain: `ok`, `degraded` or `failing`."},"changes":{"description":"The records whose state changed in this check (empty when only `health` changed).","type":"array","items":{"$ref":"#/components/schemas/DomainRecordChangeDto"}}},"required":["id","fqdn","status","health","changes"],"x-pc-sdk-model":"DomainUpdatedEventData"},"DomainVerifiedEventDataDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","description":"The domain id."},"fqdn":{"type":"string","example":"acme.com","description":"The domain name."},"status":{"type":"string","example":"pending","description":"The domain status: `pending`, `active`, `disabled`, or `deleted` on `domain.deleted`."},"health":{"type":"string","example":"ok","description":"Drift on a verified domain: `ok`, `degraded` or `failing`."},"verified_at":{"type":"string","format":"date-time","nullable":true,"example":"2026-10-17T09:20:00.000Z","description":"When the domain was verified."}},"required":["id","fqdn","status","health","verified_at"],"x-pc-sdk-model":"DomainVerifiedEventData"},"DomainDeletedEventDataDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","description":"The domain id."},"fqdn":{"type":"string","example":"acme.com","description":"The domain name."},"status":{"type":"string","example":"pending","description":"The domain status: `pending`, `active`, `disabled`, or `deleted` on `domain.deleted`."},"health":{"type":"string","example":"ok","description":"Drift on a verified domain: `ok`, `degraded` or `failing`."}},"required":["id","fqdn","status","health"],"x-pc-sdk-model":"DomainDeletedEventData"},"SuppressionAddedEventDataDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"bounce@simulator.amazonses.com","description":"The suppressed address."},"reason":{"type":"string","nullable":true,"example":"bounce","description":"Why it was suppressed (free text); null when none was given."},"source":{"type":"string","example":"bounce","description":"What added it: `manual`, `bounce` or `complaint`."},"added_at":{"type":"string","format":"date-time","example":"2026-10-17T10:00:03.000Z","description":"When it was added."}},"required":["email","reason","source","added_at"],"x-pc-sdk-model":"SuppressionAddedEventData"},"SuppressionRemovedEventDataDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"bounce@simulator.amazonses.com","description":"The address taken off the list."},"removed_at":{"type":"string","format":"date-time","example":"2026-10-17T11:00:00.000Z","description":"When it was removed."}},"required":["email","removed_at"],"x-pc-sdk-model":"SuppressionRemovedEventData"},"SendingDefaultsEventSenderDto":{"type":"object","properties":{"address":{"type":"string","example":"Acme <hello@acme.com>","description":"The default From, as set."},"domain_id":{"type":"string","format":"uuid","nullable":true,"example":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","description":"The workspace domain the address is on; null when that domain is gone."},"domain_status":{"type":"string","example":"verified","description":"Verification status of that domain (`deleted` when it is gone)."},"verified":{"type":"boolean","example":true,"description":"True when the domain can send."}},"required":["address","domain_id","domain_status","verified"],"x-pc-sdk-model":"SendingDefaultsEventSender"},"SendingDefaultsUpdatedEventDataDto":{"type":"object","properties":{"default_sender":{"nullable":true,"description":"The new default sender; null when it was cleared.","allOf":[{"$ref":"#/components/schemas/SendingDefaultsEventSenderDto"}]},"previous_address":{"type":"string","nullable":true,"example":null,"description":"The previous default From; null when there was none."},"updated_at":{"type":"string","format":"date-time","example":"2026-10-17T09:30:00.000Z","description":"When the settings changed."}},"required":["default_sender","previous_address","updated_at"],"x-pc-sdk-model":"SendingDefaultsUpdatedEventData"},"ContactEventDataDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f","description":"The contact id."},"email":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The contact's email address."},"first_name":{"type":"string","nullable":true,"example":"Ada","description":"First name; null when not set."},"last_name":{"type":"string","nullable":true,"example":"Lovelace","description":"Last name; null when not set."},"unsubscribed":{"type":"boolean","example":false,"description":"True when the contact unsubscribed from all mail."},"created_at":{"type":"string","format":"date-time","nullable":true,"example":"2026-10-24T10:00:00.000Z","description":"When the contact was created."},"updated_at":{"type":"string","format":"date-time","nullable":true,"example":"2026-10-24T11:00:00.000Z","description":"When the contact was last changed."}},"required":["id","email","first_name","last_name","unsubscribed","created_at","updated_at"],"x-pc-sdk-model":"ContactEventData"},"ContactDeletedEventDataDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f","description":"The contact id."},"email":{"type":"string","format":"email","example":"success@simulator.amazonses.com","description":"The contact's email address."},"first_name":{"type":"string","nullable":true,"example":"Ada","description":"First name; null when not set."},"last_name":{"type":"string","nullable":true,"example":"Lovelace","description":"Last name; null when not set."},"unsubscribed":{"type":"boolean","example":false,"description":"True when the contact unsubscribed from all mail."},"created_at":{"type":"string","format":"date-time","nullable":true,"example":"2026-10-24T10:00:00.000Z","description":"When the contact was created."},"updated_at":{"type":"string","format":"date-time","nullable":true,"example":"2026-10-24T11:00:00.000Z","description":"When the contact was last changed."},"deleted_at":{"type":"string","format":"date-time","example":"2026-10-24T12:00:00.000Z","description":"When the contact was deleted."}},"required":["id","email","first_name","last_name","unsubscribed","created_at","updated_at","deleted_at"],"x-pc-sdk-model":"ContactDeletedEventData"},"WebhookEventType":{"type":"string","enum":["email.sent","email.delivered","email.delivery_delayed","email.bounced","email.complained","email.failed","email.suppressed","email.skipped","email.scheduled","email.canceled","email.opened","email.clicked","email.received","domain.created","domain.updated","domain.verified","domain.deleted","suppression.added","suppression.removed","sending_defaults.updated","contact.created","contact.updated","contact.deleted"],"description":"Every event type this product sends; `x-webhooks` maps each to its payload schema. New types can be added, so treat it as open."},"WebhookEventTypeDto":{"type":"object","properties":{"type":{"example":"email.sent","description":"The event type (one of this product's catalogue).","allOf":[{"$ref":"#/components/schemas/WebhookEventType"}]},"description":{"type":"string","example":"A user signed up or was created by an admin.","description":"When this event is sent."},"category":{"type":"string","example":"Users","description":"Group shown in the event picker."},"example":{"type":"object","additionalProperties":true,"description":"An example `data` object; \"Send test\" delivers exactly this."},"emitted":{"type":"boolean","description":"False for types that can be subscribed to but are not sent yet (scheduled sends, open and click tracking, inbound)."},"legacy_alias":{"type":"string","nullable":true,"description":"The older `message.*` name for this type, still accepted in subscriptions.","example":"message.bounced"}},"x-pc-sdk-model":"WebhookEventTypeInfo","required":["type","description","category","example","emitted","legacy_alias"]},"ListWebhookEventTypesResponseDto":{"type":"object","properties":{"data":{"description":"Every event type this product sends.","type":"array","items":{"$ref":"#/components/schemas/WebhookEventTypeDto"}}},"required":["data"],"x-pc-sdk-model":"ListWebhookEventTypes"},"WebhookEndpointStatus":{"type":"string","enum":["enabled","disabled","auto_disabled"]},"WebhookEndpointDisabledReason":{"type":"string","enum":["manual","failing"]},"WebhookEndpointLegacySlot":{"type":"string","enum":["default","domain"]},"WebhookEndpointDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The endpoint's id."},"scope_type":{"type":"string","example":"workspace","description":"What owns the endpoint: `workspace`, `app` or `community`."},"scope_id":{"type":"string","description":"Id of the owning workspace, app or community."},"url":{"type":"string","format":"uri","example":"https://api.acme.com/webhooks","description":"Where events are sent."},"description":{"type":"string","nullable":true,"example":"Production receiver","description":"A label for people; null when unset."},"event_types":{"description":"Subscribed event types. Empty means every event, including types added later.","example":[],"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean","description":"The on/off switch (`PATCH … { enabled }`)."},"status":{"description":"`enabled` receives events. `disabled` was switched off. `auto_disabled` was switched off after 20 failed deliveries in a row or 24 hours of failures; `PATCH { enabled: true }` turns it back on.","allOf":[{"$ref":"#/components/schemas/WebhookEndpointStatus"}]},"disabled_at":{"type":"string","format":"date-time","nullable":true,"description":"When it was switched off; null while enabled."},"disabled_reason":{"nullable":true,"description":"`manual`: switched off by a caller. `failing`: switched off automatically after failed deliveries. Null while enabled.","allOf":[{"$ref":"#/components/schemas/WebhookEndpointDisabledReason"}]},"consecutive_failures":{"type":"number","description":"Failed automatic deliveries in a row; a success resets it."},"first_failure_at":{"type":"string","format":"date-time","nullable":true,"description":"Start of the current failure streak."},"signing_secret_hint":{"type":"string","description":"Last 4 characters of the signing secret.","example":"x9Q="},"prev_signing_secret_active":{"type":"boolean","description":"True while the previous secret still signs too (after a rotation, for its grace period)."},"prev_signing_secret_expires_at":{"type":"string","format":"date-time","nullable":true,"description":"Until then the previous secret signs too (after a rotation)."},"legacy_signature":{"type":"boolean","description":"True for endpoints carried over from the product's previous webhook system: they also receive the old signature header until its sunset date."},"created_at":{"type":"string","format":"date-time","description":"When the endpoint was created."},"updated_at":{"type":"string","format":"date-time","description":"When the endpoint last changed."},"events":{"description":"Same as `event_types`. Older name for `event_types`, accepted and returned until the legacy webhook routes are retired (Sunset: 2027-01-15). Send one of the two.","example":["email.delivered"],"type":"array","items":{"type":"string"}},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"Only events about this domain; null for every event of the workspace."},"legacy_slot":{"nullable":true,"description":"Set on the rows behind the deprecated routes: `default` (`/webhooks/default`) and `domain` (`/webhooks/domains/{id}`, which receives its domain's events instead of the default). Null for an endpoint created here.","allOf":[{"$ref":"#/components/schemas/WebhookEndpointLegacySlot"}]}},"required":["id","scope_type","scope_id","url","description","event_types","enabled","status","disabled_at","disabled_reason","consecutive_failures","first_failure_at","signing_secret_hint","prev_signing_secret_active","prev_signing_secret_expires_at","legacy_signature","created_at","updated_at","events","domain_id","legacy_slot"],"x-pc-sdk-model":"WebhookEndpoint"},"WebhookPaginationDto":{"type":"object","properties":{"next_cursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","description":"Whether another page follows."}},"required":["next_cursor","has_more"],"x-pc-sdk-model":"WebhookPagination"},"ListWebhookEndpointsResponseDto":{"type":"object","properties":{"data":{"description":"The endpoints, newest first.","type":"array","items":{"$ref":"#/components/schemas/WebhookEndpointDto"}},"pagination":{"description":"Always one page (an endpoint limit applies).","allOf":[{"$ref":"#/components/schemas/WebhookPaginationDto"}]}},"required":["data","pagination"],"x-pc-sdk-model":"ListWebhookEndpoints"},"CreateWebhookEndpointDto":{"type":"object","properties":{"url":{"type":"string","description":"Where to send events: an absolute https:// URL on a public host.","example":"https://api.acme.com/webhooks","maxLength":2048,"format":"uri"},"description":{"type":"string","nullable":true,"maxLength":200,"example":"Production receiver","description":"A label for people."},"event_types":{"type":"array","description":"Event types from `GET …/webhooks/event-types`. Empty or omitted means every event, including types added later. Older names (`message.sent`, `message.delivered`, `message.deferred`, `message.bounced`, `message.complained`, `message.failed`) are still accepted; an endpoint subscribed under one receives the event with that name as its `type`.","example":["email.sent","email.delivered"],"items":{"type":"string","enum":["email.sent","email.delivered","email.delivery_delayed","email.bounced","email.complained","email.failed","email.suppressed","email.skipped","email.scheduled","email.canceled","email.opened","email.clicked","email.received","domain.created","domain.updated","domain.verified","domain.deleted","suppression.added","suppression.removed","sending_defaults.updated","contact.created","contact.updated","contact.deleted","message.sent","message.delivered","message.deferred","message.bounced","message.complained","message.failed"]}},"enabled":{"type":"boolean","default":true,"example":true,"description":"Send `false` to create it switched off."},"events":{"type":"array","description":"Older name for `event_types`, accepted and returned until the legacy webhook routes are retired (Sunset: 2027-01-15). Send one of the two.","example":["email.delivered","email.bounced"],"items":{"type":"string","enum":["email.sent","email.delivered","email.delivery_delayed","email.bounced","email.complained","email.failed","email.suppressed","email.skipped","email.scheduled","email.canceled","email.opened","email.clicked","email.received","domain.created","domain.updated","domain.verified","domain.deleted","suppression.added","suppression.removed","sending_defaults.updated","contact.created","contact.updated","contact.deleted","message.sent","message.delivered","message.deferred","message.bounced","message.complained","message.failed"]}},"domain_id":{"type":"string","nullable":true,"format":"uuid","description":"Only events about this domain. Omit or null for every event of the workspace.","example":null}},"required":["url"]},"WebhookEndpointWithSecretDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The endpoint's id."},"scope_type":{"type":"string","example":"workspace","description":"What owns the endpoint: `workspace`, `app` or `community`."},"scope_id":{"type":"string","description":"Id of the owning workspace, app or community."},"url":{"type":"string","format":"uri","example":"https://api.acme.com/webhooks","description":"Where events are sent."},"description":{"type":"string","nullable":true,"example":"Production receiver","description":"A label for people; null when unset."},"event_types":{"description":"Subscribed event types. Empty means every event, including types added later.","example":[],"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean","description":"The on/off switch (`PATCH … { enabled }`)."},"status":{"description":"`enabled` receives events. `disabled` was switched off. `auto_disabled` was switched off after 20 failed deliveries in a row or 24 hours of failures; `PATCH { enabled: true }` turns it back on.","allOf":[{"$ref":"#/components/schemas/WebhookEndpointStatus"}]},"disabled_at":{"type":"string","format":"date-time","nullable":true,"description":"When it was switched off; null while enabled."},"disabled_reason":{"nullable":true,"description":"`manual`: switched off by a caller. `failing`: switched off automatically after failed deliveries. Null while enabled.","allOf":[{"$ref":"#/components/schemas/WebhookEndpointDisabledReason"}]},"consecutive_failures":{"type":"number","description":"Failed automatic deliveries in a row; a success resets it."},"first_failure_at":{"type":"string","format":"date-time","nullable":true,"description":"Start of the current failure streak."},"signing_secret_hint":{"type":"string","description":"Last 4 characters of the signing secret.","example":"x9Q="},"prev_signing_secret_active":{"type":"boolean","description":"True while the previous secret still signs too (after a rotation, for its grace period)."},"prev_signing_secret_expires_at":{"type":"string","format":"date-time","nullable":true,"description":"Until then the previous secret signs too (after a rotation)."},"legacy_signature":{"type":"boolean","description":"True for endpoints carried over from the product's previous webhook system: they also receive the old signature header until its sunset date."},"created_at":{"type":"string","format":"date-time","description":"When the endpoint was created."},"updated_at":{"type":"string","format":"date-time","description":"When the endpoint last changed."},"events":{"description":"Same as `event_types`. Older name for `event_types`, accepted and returned until the legacy webhook routes are retired (Sunset: 2027-01-15). Send one of the two.","example":["email.delivered"],"type":"array","items":{"type":"string"}},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"Only events about this domain; null for every event of the workspace."},"legacy_slot":{"nullable":true,"description":"Set on the rows behind the deprecated routes: `default` (`/webhooks/default`) and `domain` (`/webhooks/domains/{id}`, which receives its domain's events instead of the default). Null for an endpoint created here.","allOf":[{"$ref":"#/components/schemas/WebhookEndpointLegacySlot"}]},"signing_secret":{"type":"string","description":"The signing secret, shown once: pass it unchanged to any Standard Webhooks verifier. Store it now; it cannot be shown again.","example":"whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"}},"required":["id","scope_type","scope_id","url","description","event_types","enabled","status","disabled_at","disabled_reason","consecutive_failures","first_failure_at","signing_secret_hint","prev_signing_secret_active","prev_signing_secret_expires_at","legacy_signature","created_at","updated_at","events","domain_id","legacy_slot","signing_secret"],"x-pc-sdk-model":"WebhookEndpointWithSecret"},"UpdateWebhookEndpointDto":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"format":"uri","example":"https://api.acme.com/webhooks","description":"A new absolute https:// URL on a public host."},"description":{"type":"string","nullable":true,"maxLength":200,"example":"Production receiver","description":"A new label; null clears it."},"event_types":{"type":"array","description":"Replaces the subscription. Event types from `GET …/webhooks/event-types`. Empty or omitted means every event, including types added later. Older names (`message.sent`, `message.delivered`, `message.deferred`, `message.bounced`, `message.complained`, `message.failed`) are still accepted; an endpoint subscribed under one receives the event with that name as its `type`.","example":["email.sent","email.delivered"],"items":{"type":"string","enum":["email.sent","email.delivered","email.delivery_delayed","email.bounced","email.complained","email.failed","email.suppressed","email.skipped","email.scheduled","email.canceled","email.opened","email.clicked","email.received","domain.created","domain.updated","domain.verified","domain.deleted","suppression.added","suppression.removed","sending_defaults.updated","contact.created","contact.updated","contact.deleted","message.sent","message.delivered","message.deferred","message.bounced","message.complained","message.failed"]}},"enabled":{"type":"boolean","description":"Switch it on or off. Switching on also clears an automatic disable.","example":true},"events":{"type":"array","description":"Replaces the subscription. Older name for `event_types`, accepted and returned until the legacy webhook routes are retired (Sunset: 2027-01-15). Send one of the two.","items":{"type":"string","enum":["email.sent","email.delivered","email.delivery_delayed","email.bounced","email.complained","email.failed","email.suppressed","email.skipped","email.scheduled","email.canceled","email.opened","email.clicked","email.received","domain.created","domain.updated","domain.verified","domain.deleted","suppression.added","suppression.removed","sending_defaults.updated","contact.created","contact.updated","contact.deleted","message.sent","message.delivered","message.deferred","message.bounced","message.complained","message.failed"]}},"domain_id":{"type":"string","nullable":true,"format":"uuid","description":"Domain filter; null removes it. Not allowed on a legacy slot (its domain is what makes it one)."}}},"RotateWebhookSecretDto":{"type":"object","properties":{"grace_hours":{"type":"number","default":24,"minimum":0,"maximum":168,"description":"Hours the previous secret keeps signing too (0 ends it now).","example":24}}},"SendWebhookTestDto":{"type":"object","properties":{"event_type":{"type":"string","enum":["email.sent","email.delivered","email.delivery_delayed","email.bounced","email.complained","email.failed","email.suppressed","email.skipped","email.scheduled","email.canceled","email.opened","email.clicked","email.received","domain.created","domain.updated","domain.verified","domain.deleted","suppression.added","suppression.removed","sending_defaults.updated","contact.created","contact.updated","contact.deleted"],"description":"Which event to send; its catalogue example is the `data`.","example":"email.sent"}},"required":["event_type"]},"WebhookAttemptTrigger":{"type":"string","enum":["automatic","replay","test"]},"WebhookDeliveryAttemptDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The attempt's id."},"event_id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event that was delivered."},"endpoint_id":{"type":"string","format":"uuid","description":"The endpoint it was delivered to."},"event_type":{"type":"string","example":"user.created","description":"The event's type."},"attempt_number":{"type":"number","description":"1 for the first delivery; retries and replays count up."},"trigger":{"description":"`automatic` (first delivery or a retry), `replay` or `test`.","allOf":[{"$ref":"#/components/schemas/WebhookAttemptTrigger"}]},"url":{"type":"string","format":"uri","description":"Where it was sent."},"status_code":{"type":"number","nullable":true,"description":"HTTP status; null when no response came back."},"succeeded":{"type":"boolean","description":"True for a 2xx response."},"error_message":{"type":"string","nullable":true,"example":"request timed out","description":"Why the attempt failed when no 2xx came back; null on success."},"response_body":{"type":"string","nullable":true,"description":"The first 1 KiB of the response body."},"latency_ms":{"type":"number","nullable":true,"description":"Milliseconds until the response; null when none came back."},"attempted_at":{"type":"string","format":"date-time","description":"When the attempt was made."},"response_body_truncated":{"type":"string","nullable":true,"description":"Same as `response_body` (the first 1 KiB of the response); the older name."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The endpoint's domain filter, if it has one."}},"required":["id","event_id","endpoint_id","event_type","attempt_number","trigger","url","status_code","succeeded","error_message","response_body","latency_ms","attempted_at","response_body_truncated","domain_id"],"x-pc-sdk-model":"WebhookDeliveryAttempt"},"WebhookEventStatus":{"type":"string","enum":["pending","delivered","failed","not_sent"]},"WebhookEventDeliveryDto":{"type":"object","properties":{"endpoint_id":{"type":"string","format":"uuid","description":"The endpoint."},"attempt_number":{"type":"number","description":"Number of the latest attempt; retries and replays count up."},"status_code":{"type":"number","nullable":true,"description":"HTTP status of the latest attempt; null when no response came back."},"succeeded":{"type":"boolean","description":"True when the latest attempt got a 2xx."},"attempted_at":{"type":"string","format":"date-time","description":"When the latest attempt was made."},"next_attempt_at":{"type":"string","format":"date-time","nullable":true,"description":"When the next automatic attempt is due; null when none is queued."}},"required":["endpoint_id","attempt_number","status_code","succeeded","attempted_at","next_attempt_at"],"x-pc-sdk-model":"WebhookEventDelivery"},"WebhookEventDto":{"type":"object","properties":{"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"Sent as `webhook-id`; the same on every retry and replay."},"type":{"example":"email.sent","description":"The event type (one of this product's catalogue).","allOf":[{"$ref":"#/components/schemas/WebhookEventType"}]},"created_at":{"type":"string","format":"date-time","description":"When the event happened."},"test":{"type":"boolean","description":"Made by \"Send test\"."},"status":{"description":"`pending`: a delivery is queued. `failed`: the latest attempt to some endpoint failed and none is queued. `delivered`: every endpoint answered 2xx. `not_sent`: no endpoint subscribed.","allOf":[{"$ref":"#/components/schemas/WebhookEventStatus"}]},"payload":{"type":"object","additionalProperties":true,"description":"The JSON body exactly as sent."},"deliveries":{"description":"Latest attempt per endpoint (an endpoint whose first attempt is still queued is not listed yet).","type":"array","items":{"$ref":"#/components/schemas/WebhookEventDeliveryDto"}},"email_id":{"type":"string","format":"uuid","nullable":true,"description":"The email the event is about, when there is one."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The domain the event is about."}},"required":["id","type","created_at","test","status","payload","deliveries","email_id","domain_id"],"x-pc-sdk-model":"WebhookEvent"},"ListWebhookEventsResponseDto":{"type":"object","properties":{"data":{"description":"The events, newest first.","type":"array","items":{"$ref":"#/components/schemas/WebhookEventDto"}},"pagination":{"description":"The cursor for the next page.","allOf":[{"$ref":"#/components/schemas/WebhookPaginationDto"}]}},"required":["data","pagination"],"x-pc-sdk-model":"ListWebhookEvents"},"WebhookEventDetailDto":{"type":"object","properties":{"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"Sent as `webhook-id`; the same on every retry and replay."},"type":{"example":"email.sent","description":"The event type (one of this product's catalogue).","allOf":[{"$ref":"#/components/schemas/WebhookEventType"}]},"created_at":{"type":"string","format":"date-time","description":"When the event happened."},"test":{"type":"boolean","description":"Made by \"Send test\"."},"status":{"description":"`pending`: a delivery is queued. `failed`: the latest attempt to some endpoint failed and none is queued. `delivered`: every endpoint answered 2xx. `not_sent`: no endpoint subscribed.","allOf":[{"$ref":"#/components/schemas/WebhookEventStatus"}]},"payload":{"type":"object","additionalProperties":true,"description":"The JSON body exactly as sent."},"deliveries":{"description":"Latest attempt per endpoint (an endpoint whose first attempt is still queued is not listed yet).","type":"array","items":{"$ref":"#/components/schemas/WebhookEventDeliveryDto"}},"email_id":{"type":"string","format":"uuid","nullable":true,"description":"The email the event is about, when there is one."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The domain the event is about."},"attempts":{"description":"Every attempt, newest first.","type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryAttemptDto"}}},"required":["id","type","created_at","test","status","payload","deliveries","email_id","domain_id","attempts"],"x-pc-sdk-model":"WebhookEventDetail"},"ReplayWebhookEventResponseDto":{"type":"object","properties":{"event_id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","description":"The replayed event (the same id as the original)."},"attempts":{"description":"One attempt per endpoint it was sent to.","type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryAttemptDto"}}},"required":["event_id","attempts"],"x-pc-sdk-model":"ReplayWebhookEvent"},"StatsWindow":{"type":"string","enum":["1d","7d","30d"]},"MailStatsTotalsDto":{"type":"object","properties":{"domains":{"type":"number","description":"Domains registered in the workspace.","example":3},"verified_domains":{"type":"number","description":"Domains whose `verification_status` is `verified` (active and healthy). A verified domain whose required record went missing (`temporary_failure`) is not counted here; it is in `attention_domains`.","example":2},"attention_domains":{"type":"number","description":"Domains whose `verification_status` is `temporary_failure` or `failed`: a required DNS record is missing or wrong and needs fixing. The rest (`domains` minus `verified_domains` minus this) are still pending or disabled.","example":1}},"required":["domains","verified_domains","attention_domains"],"x-pc-sdk-model":"MailStatsTotals"},"MailStatsInWindowDto":{"type":"object","properties":{"sent":{"type":"number","description":"Messages that left the queue: sent + delivered + bounced + complained + failed + deferred + suppressed. Same as the deliverability `left_queue`.","example":1180},"emails":{"type":"number","description":"Emails sent, exactly as `GET /emails/metrics` counts `sent`: statuses sent, delivered, deferred, bounced and complained. Excludes failed and suppressed, so it can be lower than `sent`. The denominator of `bounce_rate`.","example":1173},"delivered":{"type":"number","description":"Messages with status `delivered` (a delivery confirmation came back). Same as the deliverability `confirmed`; complained messages are not included here (they are in `GET /emails/metrics`).","example":1100},"bounced":{"type":"number","description":"Messages hard-bounced.","example":12},"complained":{"type":"number","description":"Messages the recipient marked as spam, as reported by their mailbox provider.","example":1},"deferred":{"type":"number","description":"Messages currently deferred.","example":3},"suppressed":{"type":"number","description":"Messages not sent because the recipient is suppressed.","example":5},"unconfirmed":{"type":"number","description":"Messages handed off with nothing back in either direction (status `sent`). Not a synonym for delivered.","example":60},"failed":{"type":"number","description":"Failed to send: messages refused on our side before they reached any recipient's mail server (status `failed`), exactly as `GET /emails/metrics` counts `failed`. Not in `emails` or `tracked`, so never in a rate.","example":0},"tracked":{"type":"number","description":"Emails with delivery tracking, exactly as `GET /emails/metrics` counts `tracked`: the denominator of `delivery_rate`.","example":1150},"delivery_rate":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Deliverability rate, 0 to 1: delivered (incl. complained) / `tracked` (emails sent with delivery tracking), as `GET /emails/metrics` defines it. Emails that failed to send (`failed`) are not counted. Null when no mail in the window has delivery tracking.","example":0.974},"bounce_rate":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Bounce rate, 0 to 1: bounced / emails sent (sent, delivered, deferred, bounced, complained — narrower than `sent` above, which also counts failed and suppressed). Null when nothing was sent.","example":0.0185},"complaint_rate":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Complaint rate, 0 to 1: complained / delivered. Null without mail with delivery tracking or when nothing was delivered.","example":0.0001}},"required":["sent","emails","delivered","bounced","complained","deferred","suppressed","unconfirmed","failed","tracked","delivery_rate","bounce_rate","complaint_rate"],"x-pc-sdk-model":"MailStatsInWindow"},"StatsSeriesMetric":{"type":"string","enum":["sent"]},"StatsGranularity":{"type":"string","enum":["day"]},"StatsSeriesPointDto":{"type":"object","properties":{"date":{"type":"string","description":"UTC calendar day.","format":"date","example":"2026-10-07"},"value":{"type":"number","description":"Value for that day.","example":42}},"required":["date","value"],"x-pc-sdk-model":"StatsSeriesPoint"},"MailStatsSeriesDto":{"type":"object","properties":{"metric":{"description":"Messages that left the queue, per UTC day of `created_at` (same statuses as `in_window.sent`).","example":"sent","allOf":[{"$ref":"#/components/schemas/StatsSeriesMetric"}]},"granularity":{"description":"Bucket width.","example":"day","allOf":[{"$ref":"#/components/schemas/StatsGranularity"}]},"points":{"description":"Dense and zero-filled: one point per UTC day in the window, oldest first, ending today.","type":"array","items":{"$ref":"#/components/schemas/StatsSeriesPointDto"}}},"required":["metric","granularity","points"],"x-pc-sdk-model":"MailStatsSeries"},"MailWorkspaceStatsDto":{"type":"object","properties":{"window":{"description":"Window the counts cover.","example":"30d","allOf":[{"$ref":"#/components/schemas/StatsWindow"}]},"generated_at":{"type":"string","format":"date-time","description":"When these numbers were computed. Responses are cached for up to 60 seconds.","example":"2026-10-07T09:00:00.000Z"},"last_activity_at":{"type":"string","format":"date-time","nullable":true,"description":"Most recent outbound message `created_at` still on record (30-day retention). Null when none.","example":"2026-10-07T08:41:12.000Z"},"totals":{"description":"All-time counts.","allOf":[{"$ref":"#/components/schemas/MailStatsTotalsDto"}]},"in_window":{"description":"Outbound counts in the window.","allOf":[{"$ref":"#/components/schemas/MailStatsInWindowDto"}]},"series":{"description":"Daily sent messages.","allOf":[{"$ref":"#/components/schemas/MailStatsSeriesDto"}]}},"required":["window","generated_at","last_activity_at","totals","in_window","series"],"x-pc-sdk-model":"MailWorkspaceStats"},"EmailMetricsObject":{"type":"string","enum":["metrics"]},"EmailMetricsGranularity":{"type":"string","enum":["hourly","daily"]},"EmailMetricsMeasuredDto":{"type":"object","properties":{"delivery":{"type":"boolean","description":"True when some mail in the range has delivery tracking. False when every email in the range was sent before delivery tracking started or through a custom SMTP relay, which confirms hand-off, not delivery; `delivered` and `delivery_rate` are then not measured.","example":true},"complaint":{"type":"boolean","description":"True when complaints can be measured: they arrive through mailbox providers' feedback loops, so this needs mail with delivery tracking in the range.","example":true}},"required":["delivery","complaint"],"x-pc-sdk-model":"EmailMetricsMeasured"},"BounceSource":{"type":"string","enum":["relay","ses","mixed","none"]},"EmailMetricsCountersDto":{"type":"object","properties":{"sent":{"type":"number","description":"Emails: messages that left the queue (status sent, delivered, deferred, bounced or complained). Excludes queued, failed, suppressed and template test sends.","example":29037},"delivered":{"type":"number","description":"Messages the recipient’s mail server confirmed (delivered + complained; a complaint implies delivery). Counted for mail with delivery tracking only.","example":1240},"deferred":{"type":"number","description":"Messages still being retried (status deferred).","example":3},"bounced":{"type":"number","description":"Messages that bounced. Tracked mail's bounces are matched by message id; bounce capture for untracked mail is partial (see `bounce_source`).","example":12},"complained":{"type":"number","description":"Messages the recipient marked as spam, as reported by their mailbox provider.","example":1},"failed":{"type":"number","description":"Failed to send: messages refused on our side before they reached any recipient's mail server (for example a From domain that was not verified yet, or a template that could not render). Not in `sent` or `tracked`, so never in the deliverability, bounce or complaint rate; reported here so they stay visible. Each email's reason is on its event timeline (`GET /emails/{id}`).","example":0},"suppressed":{"type":"number","description":"Messages not sent because the recipient is on the suppression list. Not in `sent`, never in the bounce rate.","example":5},"unconfirmed":{"type":"number","description":"Messages that left us with no outcome back yet (status sent). Not a synonym for delivered.","example":60},"tracked":{"type":"number","description":"Emails with delivery tracking: the part of `sent` that was handed off with the message id the recipient server's report is matched on. The deliverability-rate denominator. Mail sent through a custom SMTP relay, or before delivery tracking started, is in `sent` but not here; emails that failed to send (`failed`) are in neither.","example":1273},"delivery_rate":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Deliverability rate: `delivered` / `tracked` (emails with delivery tracking; complaints count as delivered). Measures what recipients' mail servers did with mail that was handed off: emails that failed to send (`failed`) are not counted. A number from 0 to 1 (0.0185 = 1.85 %), or null when it cannot be measured or its denominator is zero.","example":0.974},"bounce_rate":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Bounce rate: `bounced` / `sent` (emails that failed to send are not in `sent`). 5 % or more puts sending at risk; 4 % is the risk line. A number from 0 to 1 (0.0185 = 1.85 %), or null when it cannot be measured or its denominator is zero.","example":0.0185},"complaint_rate":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Complaint rate: `complained` / `delivered`. 0.1 % or more puts sending at risk; 0.08 % is the risk line. Null without mail with delivery tracking. A number from 0 to 1 (0.0185 = 1.85 %), or null when it cannot be measured or its denominator is zero.","example":0.0001}},"required":["sent","delivered","deferred","bounced","complained","failed","suppressed","unconfirmed","tracked","delivery_rate","bounce_rate","complaint_rate"],"x-pc-sdk-model":"EmailMetricsCounters"},"EmailMetricsDataItemDto":{"type":"object","properties":{"sent":{"type":"number","description":"Emails: messages that left the queue (status sent, delivered, deferred, bounced or complained). Excludes queued, failed, suppressed and template test sends.","example":29037},"delivered":{"type":"number","description":"Messages the recipient’s mail server confirmed (delivered + complained; a complaint implies delivery). Counted for mail with delivery tracking only.","example":1240},"deferred":{"type":"number","description":"Messages still being retried (status deferred).","example":3},"bounced":{"type":"number","description":"Messages that bounced. Tracked mail's bounces are matched by message id; bounce capture for untracked mail is partial (see `bounce_source`).","example":12},"complained":{"type":"number","description":"Messages the recipient marked as spam, as reported by their mailbox provider.","example":1},"failed":{"type":"number","description":"Failed to send: messages refused on our side before they reached any recipient's mail server (for example a From domain that was not verified yet, or a template that could not render). Not in `sent` or `tracked`, so never in the deliverability, bounce or complaint rate; reported here so they stay visible. Each email's reason is on its event timeline (`GET /emails/{id}`).","example":0},"suppressed":{"type":"number","description":"Messages not sent because the recipient is on the suppression list. Not in `sent`, never in the bounce rate.","example":5},"unconfirmed":{"type":"number","description":"Messages that left us with no outcome back yet (status sent). Not a synonym for delivered.","example":60},"tracked":{"type":"number","description":"Emails with delivery tracking: the part of `sent` that was handed off with the message id the recipient server's report is matched on. The deliverability-rate denominator. Mail sent through a custom SMTP relay, or before delivery tracking started, is in `sent` but not here; emails that failed to send (`failed`) are in neither.","example":1273},"delivery_rate":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Deliverability rate: `delivered` / `tracked` (emails with delivery tracking; complaints count as delivered). Measures what recipients' mail servers did with mail that was handed off: emails that failed to send (`failed`) are not counted. A number from 0 to 1 (0.0185 = 1.85 %), or null when it cannot be measured or its denominator is zero.","example":0.974},"bounce_rate":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Bounce rate: `bounced` / `sent` (emails that failed to send are not in `sent`). 5 % or more puts sending at risk; 4 % is the risk line. A number from 0 to 1 (0.0185 = 1.85 %), or null when it cannot be measured or its denominator is zero.","example":0.0185},"complaint_rate":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Complaint rate: `complained` / `delivered`. 0.1 % or more puts sending at risk; 0.08 % is the risk line. Null without mail with delivery tracking. A number from 0 to 1 (0.0185 = 1.85 %), or null when it cannot be measured or its denominator is zero.","example":0.0001},"period":{"type":"string","format":"date-time","nullable":true,"description":"Bucket start, in `timezone`’s offset. Null when `dimensions` does not include `period`.","example":"2026-10-12T00:00:00+01:00"},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"Sending domain (`domain.id`). Present with the `domain` dimension; null for mail with no registered domain.","example":"3f6b2a1e-8c4d-4e5f-9a0b-1c2d3e4f5a6b"},"domain_name":{"type":"string","nullable":true,"description":"The domain’s name. Present with the `domain` dimension; null when the domain was deleted or there is none.","example":"mail.example.com"}},"required":["sent","delivered","deferred","bounced","complained","failed","suppressed","unconfirmed","tracked","delivery_rate","bounce_rate","complaint_rate","period"],"x-pc-sdk-model":"EmailMetricsDataItem"},"EmailMetricsResponseDto":{"type":"object","properties":{"object":{"description":"Object type.","example":"metrics","allOf":[{"$ref":"#/components/schemas/EmailMetricsObject"}]},"start_date":{"type":"string","format":"date-time","description":"Resolved start of the range (inclusive), in `timezone`’s offset.","example":"2026-10-06T00:00:00+01:00"},"end_date":{"type":"string","format":"date-time","description":"Resolved end of the range (exclusive), in `timezone`’s offset.","example":"2026-10-12T15:00:00+01:00"},"timezone":{"type":"string","description":"IANA time zone of the buckets.","example":"Europe/Lisbon"},"granularity":{"description":"Bucket width used.","example":"daily","allOf":[{"$ref":"#/components/schemas/EmailMetricsGranularity"}]},"measured":{"description":"Which rates this range can measure at all.","allOf":[{"$ref":"#/components/schemas/EmailMetricsMeasuredDto"}]},"bounce_source":{"description":"How bounces were captured for the sent mail: `ses` (delivery tracking; bounces matched by message id), `relay` (emails sent before delivery tracking started, or through a custom SMTP relay; partial capture), `mixed`, or `none` (nothing sent).","example":"ses","allOf":[{"$ref":"#/components/schemas/BounceSource"}]},"totals":{"description":"Counts and rates over the whole range.","allOf":[{"$ref":"#/components/schemas/EmailMetricsCountersDto"}]},"data":{"description":"The breakdown `dimensions` asks for, oldest bucket first, then by domain name. With `period`, every bucket is present (zero-filled).","type":"array","items":{"$ref":"#/components/schemas/EmailMetricsDataItemDto"}}},"required":["object","start_date","end_date","timezone","granularity","measured","bounce_source","totals","data"],"x-pc-sdk-model":"EmailMetrics"},"SmtpConfigStatus":{"type":"string","enum":["pending","active","failed"]},"SmtpConfigDto":{"type":"object","properties":{"workspace_id":{"type":"string","description":"The workspace the configuration belongs to.","format":"uuid"},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"Null for the workspace-default config, set for a per-domain override."},"host":{"type":"string","description":"SMTP server host name."},"port":{"type":"number","description":"SMTP server port."},"secure":{"type":"boolean","description":"True for implicit TLS (usually port 465); false for STARTTLS or plain."},"username":{"type":"string","description":"SMTP user name; null when the server needs no authentication.","nullable":true},"password":{"type":"string","nullable":true,"description":"Always null on the wire — the stored ciphertext is never returned."},"password_set":{"type":"boolean","description":"True when a password is stored (it is never returned)."},"from_name":{"type":"string","description":"Sender display name used for mail sent through this server."},"from_email":{"type":"string","description":"Sender address used for mail sent through this server.","format":"email"},"status":{"description":"`pending` until the connection is verified, then `active`; `failed` when the last check failed.","allOf":[{"$ref":"#/components/schemas/SmtpConfigStatus"}]},"last_verified_at":{"type":"string","description":"When the connection last verified; null if never.","format":"date-time","nullable":true},"last_verify_error":{"type":"string","description":"Why the last verification failed; null when it passed.","nullable":true},"created_at":{"type":"string","description":"When the configuration was created.","format":"date-time"},"updated_at":{"type":"string","description":"When the configuration was last changed.","format":"date-time"}},"required":["workspace_id","domain_id","host","port","secure","username","password","password_set","from_name","from_email","status","last_verified_at","last_verify_error","created_at","updated_at"],"x-pc-sdk-model":"SmtpConfig"},"GetSmtpConfigResponseDto":{"type":"object","properties":{"data":{"nullable":true,"description":"Null when this workspace has not configured SMTP.","allOf":[{"$ref":"#/components/schemas/SmtpConfigDto"}]}},"required":["data"],"x-pc-sdk-model":"GetSmtpConfig"},"UpsertSmtpConfigDto":{"type":"object","properties":{"host":{"type":"string","description":"SMTP server hostname.","example":"smtp.sendgrid.net","minLength":1,"maxLength":255},"port":{"type":"number","description":"SMTP server port (commonly 587 for STARTTLS, 465 for implicit TLS).","example":587,"minimum":1,"maximum":65535},"secure":{"type":"boolean","description":"Whether to use implicit TLS (true → port 465 style). For STARTTLS on 587, set false.","example":false},"username":{"type":"string","description":"SMTP username. May be omitted alongside password for anonymous SMTP (e.g. postfix on a private network); otherwise both are required.","minLength":1,"maxLength":255},"password":{"type":"string","description":"SMTP password. Stored encrypted at rest; never returned by GET endpoints.","minLength":1,"maxLength":1024},"from_name":{"type":"string","description":"Default From name on outbound messages.","example":"Acme Notifications","minLength":1,"maxLength":100},"from_email":{"type":"string","description":"Default From email address. Must be authorized to send on the chosen domain.","format":"email","example":"noreply@acme.com","minLength":1,"maxLength":255}},"required":["host","port","secure","from_name","from_email"]},"VerifySmtpConfigDto":{"type":"object","properties":{"host":{"type":"string","description":"SMTP server hostname.","example":"smtp.sendgrid.net","minLength":1,"maxLength":255},"port":{"type":"number","description":"SMTP server port (commonly 587 for STARTTLS, 465 for implicit TLS).","example":587,"minimum":1,"maximum":65535},"secure":{"type":"boolean","description":"Whether to use implicit TLS (true → port 465 style). For STARTTLS on 587, set false.","example":false},"username":{"type":"string","description":"SMTP username. May be omitted alongside password for anonymous SMTP (e.g. postfix on a private network); otherwise both are required.","minLength":1,"maxLength":255},"password":{"type":"string","description":"SMTP password. Stored encrypted at rest; never returned by GET endpoints.","minLength":1,"maxLength":1024},"from_name":{"type":"string","description":"Default From name on outbound messages.","example":"Acme Notifications","minLength":1,"maxLength":100},"from_email":{"type":"string","description":"Default From email address. Must be authorized to send on the chosen domain.","format":"email","example":"noreply@acme.com","minLength":1,"maxLength":255}},"required":["host","port","secure","from_name","from_email"]},"SmtpVerifyErrorDto":{"type":"object","properties":{"code":{"type":"string","description":"Error code from the SMTP client (for example `EAUTH`).","example":"EAUTH"},"message":{"type":"string","description":"What went wrong, in plain words.","example":"Authentication failed — check the username and password."}},"required":["code","message"],"x-pc-sdk-model":"SmtpVerifyError"},"SmtpVerifyResultDto":{"type":"object","properties":{"ok":{"type":"boolean","description":"True when the server accepted the connection and login."},"error":{"description":"The failure; absent when `ok` is true.","nullable":true,"allOf":[{"$ref":"#/components/schemas/SmtpVerifyErrorDto"}]}},"required":["ok"],"x-pc-sdk-model":"SmtpVerifyResult"},"ListSmtpConfigsResponseDto":{"type":"object","properties":{"data":{"description":"The SMTP configurations: the workspace one and any per-domain overrides.","type":"array","items":{"$ref":"#/components/schemas/SmtpConfigDto"}}},"required":["data"],"x-pc-sdk-model":"ListSmtpConfigs"},"AddSuppressionDto":{"type":"object","properties":{"email":{"type":"string","description":"Address to suppress. Once listed, sends to it are dropped before delivery.","format":"email","example":"bounced@example.com"},"reason":{"type":"string","description":"Why it was suppressed. Free text, for the operator reading the list later.","maxLength":255,"example":"hard bounce"}},"required":["email"]},"SuppressionSource":{"type":"string","enum":["manual","bounce","complaint"]},"SuppressionEntryDto":{"type":"object","properties":{"id":{"type":"string","description":"Suppression row id.","format":"uuid"},"workspace_id":{"type":"string","description":"Workspace this suppression belongs to.","format":"uuid"},"email":{"type":"string","description":"Suppressed recipient (lowercased on insert).","format":"email","example":"user@example.com"},"reason":{"type":"string","description":"Free-text reason; null when unspecified.","nullable":true},"source":{"description":"Where the row originated.","allOf":[{"$ref":"#/components/schemas/SuppressionSource"}]},"added_at":{"type":"string","description":"Insertion (or last-touch) timestamp.","format":"date-time"}},"required":["id","workspace_id","email","reason","source","added_at"],"x-pc-sdk-model":"SuppressionEntry"},"ListSuppressionResponseDto":{"type":"object","properties":{"data":{"description":"The suppressed addresses on this page.","type":"array","items":{"$ref":"#/components/schemas/SuppressionEntryDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListSuppression"},"CreateMailboxDto":{"type":"object","properties":{"local_part":{"type":"string","description":"Local part of the address (portion before @)","example":"claude-qa-alpha"},"domain_id":{"type":"string","description":"Domain ID.","format":"uuid"},"retention_days":{"type":"number","description":"Retention period in days (1–30)","minimum":1,"maximum":30},"display_name":{"type":"string","description":"Human-readable display name"}},"required":["local_part","domain_id"]},"MailboxStatus":{"type":"string","enum":["active","disabled"]},"MailboxDto":{"type":"object","properties":{"id":{"type":"string","description":"The mailbox id.","format":"uuid"},"seq_id":{"type":"string","description":"Sequential id per workspace (stable, monotonic).","example":"7"},"workspace_id":{"type":"string","description":"The workspace that owns the mailbox.","format":"uuid"},"domain_id":{"type":"string","description":"The domain the mailbox receives on.","format":"uuid"},"local_part":{"type":"string","description":"The part before the @ of the mailbox address."},"display_name":{"type":"string","description":"Display name of the mailbox; null for none.","nullable":true},"owner_account_id":{"type":"string","description":"Platform account that created the mailbox; null when created with an API key.","format":"uuid","nullable":true},"retention_days":{"type":"number","description":"Retention period in days.","example":14},"status":{"description":"`active` mailboxes receive mail; `disabled` ones reject it.","example":"active","allOf":[{"$ref":"#/components/schemas/MailboxStatus"}]},"created_at":{"type":"string","description":"When the mailbox was created.","format":"date-time"}},"required":["id","seq_id","workspace_id","domain_id","local_part","display_name","owner_account_id","retention_days","status","created_at"],"x-pc-sdk-model":"Mailbox"},"ListMailboxesResponseDto":{"type":"object","properties":{"data":{"description":"The mailboxes on this page.","type":"array","items":{"$ref":"#/components/schemas/MailboxDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListMailboxes"},"UpdateMailboxDto":{"type":"object","properties":{"display_name":{"type":"string","description":"Display name"},"retention_days":{"type":"number","description":"Retention period in days (1–30)","minimum":1,"maximum":30},"status":{"type":"string","description":"Mailbox status","enum":["active","disabled"]}}},"MessageDto":{"type":"object","properties":{"id":{"type":"string","description":"The message id.","format":"uuid"},"mailbox_id":{"type":"string","description":"The mailbox the message was delivered to.","format":"uuid"},"seq_id":{"type":"string","description":"Sequential ID per mailbox.","example":"42"},"raw_object_key":{"type":"string","description":"Storage object key for the raw RFC5322 .eml."},"envelope_to":{"type":"string","description":"The SMTP envelope recipient."},"from_address":{"type":"string","description":"Sender address from the From header."},"from_local":{"type":"string","description":"Part of the sender address before the @."},"from_domain":{"type":"string","description":"Domain of the sender address."},"to_addresses":{"description":"Addresses from the To header.","type":"array","items":{"type":"string"}},"cc_addresses":{"description":"Addresses from the Cc header.","type":"array","items":{"type":"string"}},"subject":{"type":"string","description":"Subject line; null when the message has none.","nullable":true},"body_preview":{"type":"string","nullable":true,"description":"First 512 bytes of the plaintext body. This is message content, not metadata, so it is only populated for callers holding `mail.message.body.read`; everyone else sees null. The full body is at /:mid/raw, behind the same action."},"rfc822_message_id":{"type":"string","description":"The Message-ID header; null when missing.","nullable":true},"size_bytes":{"type":"number","description":"Size of the raw message in bytes."},"spam_score":{"type":"string","description":"Spam score from the receiving filter; null when not scored.","nullable":true},"spam_verdict":{"type":"string","description":"Spam verdict from the receiving filter; null when not scored.","nullable":true},"spf_result":{"type":"string","description":"SPF result for the sender; null when not checked.","nullable":true},"dkim_result":{"type":"string","description":"DKIM result; null when not checked.","nullable":true},"dmarc_result":{"type":"string","description":"DMARC result; null when not checked.","nullable":true},"quarantined":{"type":"boolean","description":"True when the message was quarantined as spam or malware."},"received_at":{"type":"string","description":"When the message arrived.","format":"date-time"},"read_at":{"type":"string","description":"When the message was marked read; null while unread.","format":"date-time","nullable":true},"deleted_at":{"type":"string","description":"When the message was deleted; null while not deleted.","format":"date-time","nullable":true}},"required":["id","mailbox_id","seq_id","raw_object_key","envelope_to","from_address","from_local","from_domain","to_addresses","cc_addresses","subject","body_preview","rfc822_message_id","size_bytes","spam_score","spam_verdict","spf_result","dkim_result","dmarc_result","quarantined","received_at","read_at","deleted_at"],"x-pc-sdk-model":"Message"},"ListMessagesResponseDto":{"type":"object","properties":{"data":{"description":"The messages on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/MessageDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListMessages"},"MessageAttachmentDto":{"type":"object","properties":{"position":{"type":"number","description":"Position of the attachment in the message, starting at 0; used to download it."},"filename":{"type":"string","description":"File name of the attachment; null when it has none.","nullable":true},"content_id":{"type":"string","description":"Content-ID of an inline attachment; null otherwise.","nullable":true},"content_type":{"type":"string","description":"MIME type of the attachment."},"size_bytes":{"type":"number","description":"Size of the attachment in bytes."},"sha256":{"type":"string","description":"SHA-256 of the attachment, hex encoded."}},"required":["position","filename","content_id","content_type","size_bytes","sha256"],"x-pc-sdk-model":"MessageAttachment"},"MessageDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"The message id.","format":"uuid"},"mailbox_id":{"type":"string","description":"The mailbox the message was delivered to.","format":"uuid"},"seq_id":{"type":"string","description":"Sequential ID per mailbox.","example":"42"},"raw_object_key":{"type":"string","description":"Storage object key for the raw RFC5322 .eml."},"envelope_to":{"type":"string","description":"The SMTP envelope recipient."},"from_address":{"type":"string","description":"Sender address from the From header."},"from_local":{"type":"string","description":"Part of the sender address before the @."},"from_domain":{"type":"string","description":"Domain of the sender address."},"to_addresses":{"description":"Addresses from the To header.","type":"array","items":{"type":"string"}},"cc_addresses":{"description":"Addresses from the Cc header.","type":"array","items":{"type":"string"}},"subject":{"type":"string","description":"Subject line; null when the message has none.","nullable":true},"body_preview":{"type":"string","nullable":true,"description":"First 512 bytes of the plaintext body. This is message content, not metadata, so it is only populated for callers holding `mail.message.body.read`; everyone else sees null. The full body is at /:mid/raw, behind the same action."},"rfc822_message_id":{"type":"string","description":"The Message-ID header; null when missing.","nullable":true},"size_bytes":{"type":"number","description":"Size of the raw message in bytes."},"spam_score":{"type":"string","description":"Spam score from the receiving filter; null when not scored.","nullable":true},"spam_verdict":{"type":"string","description":"Spam verdict from the receiving filter; null when not scored.","nullable":true},"spf_result":{"type":"string","description":"SPF result for the sender; null when not checked.","nullable":true},"dkim_result":{"type":"string","description":"DKIM result; null when not checked.","nullable":true},"dmarc_result":{"type":"string","description":"DMARC result; null when not checked.","nullable":true},"quarantined":{"type":"boolean","description":"True when the message was quarantined as spam or malware."},"received_at":{"type":"string","description":"When the message arrived.","format":"date-time"},"read_at":{"type":"string","description":"When the message was marked read; null while unread.","format":"date-time","nullable":true},"deleted_at":{"type":"string","description":"When the message was deleted; null while not deleted.","format":"date-time","nullable":true},"attachments":{"description":"The message's attachments.","type":"array","items":{"$ref":"#/components/schemas/MessageAttachmentDto"}}},"required":["id","mailbox_id","seq_id","raw_object_key","envelope_to","from_address","from_local","from_domain","to_addresses","cc_addresses","subject","body_preview","rfc822_message_id","size_bytes","spam_score","spam_verdict","spf_result","dkim_result","dmarc_result","quarantined","received_at","read_at","deleted_at","attachments"],"x-pc-sdk-model":"MessageDetail"},"SpamVerdict":{"type":"string","enum":["ham","junk","reject"]},"ReceivedEmailDto":{"type":"object","properties":{"id":{"type":"string","description":"The received email id.","format":"uuid","example":"7d9c1e2a-3b4c-4d5e-8f6a-7b8c9d0e1f2a"},"mailbox_id":{"type":"string","format":"uuid","description":"The mailbox that received it."},"mailbox_address":{"type":"string","format":"email","description":"The receiving mailbox address (`local_part@domain`).","example":"support@in.example.com"},"from":{"type":"string","description":"Sender address (the From header).","example":"jane@example.org"},"to":{"description":"Addresses in the To header.","example":["support@in.example.com"],"type":"array","items":{"type":"string"}},"cc":{"description":"Addresses in the Cc header.","example":[],"type":"array","items":{"type":"string"}},"subject":{"type":"string","description":"Subject line; null when the email has none.","nullable":true,"example":"Invoice #42"},"rfc822_message_id":{"type":"string","nullable":true,"description":"The RFC 822 Message-ID header, as received.","example":"<CAF1234@mail.gmail.com>"},"received_at":{"type":"string","description":"When the email arrived.","format":"date-time"},"read_at":{"type":"string","format":"date-time","nullable":true,"description":"When it was marked read; null while unread."},"spam_verdict":{"nullable":true,"description":"The spam filter's verdict; null when the filter did not run.","example":"ham","allOf":[{"$ref":"#/components/schemas/SpamVerdict"}]},"spam":{"type":"boolean","description":"True when the spam filter quarantined it (verdict `junk` or `reject`).","example":false},"spf_result":{"type":"string","nullable":true,"description":"SPF result for the sender, e.g. `pass`, `fail`, `softfail`, `none`.","example":"pass"},"dkim_result":{"type":"string","nullable":true,"description":"DKIM result, e.g. `pass`, `fail`, `none`.","example":"pass"},"dmarc_result":{"type":"string","nullable":true,"description":"DMARC result, e.g. `pass`, `fail`, `none`.","example":"pass"},"size_bytes":{"type":"number","description":"Size of the raw message in bytes.","example":5120},"attachment_count":{"type":"number","description":"Number of attachments.","example":1}},"required":["id","mailbox_id","mailbox_address","from","to","cc","subject","rfc822_message_id","received_at","read_at","spam_verdict","spam","spf_result","dkim_result","dmarc_result","size_bytes","attachment_count"],"x-pc-sdk-model":"ReceivedEmail"},"ListReceivedEmailsResponseDto":{"type":"object","properties":{"data":{"description":"The received emails on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/ReceivedEmailDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListReceivedEmails"},"ReceivedEmailAttachmentDto":{"type":"object","properties":{"position":{"type":"number","description":"Position in the message; the `{pos}` of the attachment download route.","example":0},"filename":{"type":"string","description":"File name of the attachment; null when it has none.","nullable":true,"example":"invoice.pdf"},"content_id":{"type":"string","nullable":true,"description":"Content-ID for inline parts."},"content_type":{"type":"string","description":"MIME type of the attachment.","example":"application/pdf"},"size_bytes":{"type":"number","description":"Size of the attachment in bytes.","example":48213},"sha256":{"type":"string","description":"SHA-256 of the attachment bytes, hex."}},"required":["position","filename","content_id","content_type","size_bytes","sha256"],"x-pc-sdk-model":"ReceivedEmailAttachment"},"ReceivedEmailDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"The received email id.","format":"uuid","example":"7d9c1e2a-3b4c-4d5e-8f6a-7b8c9d0e1f2a"},"mailbox_id":{"type":"string","format":"uuid","description":"The mailbox that received it."},"mailbox_address":{"type":"string","format":"email","description":"The receiving mailbox address (`local_part@domain`).","example":"support@in.example.com"},"from":{"type":"string","description":"Sender address (the From header).","example":"jane@example.org"},"to":{"description":"Addresses in the To header.","example":["support@in.example.com"],"type":"array","items":{"type":"string"}},"cc":{"description":"Addresses in the Cc header.","example":[],"type":"array","items":{"type":"string"}},"subject":{"type":"string","description":"Subject line; null when the email has none.","nullable":true,"example":"Invoice #42"},"rfc822_message_id":{"type":"string","nullable":true,"description":"The RFC 822 Message-ID header, as received.","example":"<CAF1234@mail.gmail.com>"},"received_at":{"type":"string","description":"When the email arrived.","format":"date-time"},"read_at":{"type":"string","format":"date-time","nullable":true,"description":"When it was marked read; null while unread."},"spam_verdict":{"nullable":true,"description":"The spam filter's verdict; null when the filter did not run.","example":"ham","allOf":[{"$ref":"#/components/schemas/SpamVerdict"}]},"spam":{"type":"boolean","description":"True when the spam filter quarantined it (verdict `junk` or `reject`).","example":false},"spf_result":{"type":"string","nullable":true,"description":"SPF result for the sender, e.g. `pass`, `fail`, `softfail`, `none`.","example":"pass"},"dkim_result":{"type":"string","nullable":true,"description":"DKIM result, e.g. `pass`, `fail`, `none`.","example":"pass"},"dmarc_result":{"type":"string","nullable":true,"description":"DMARC result, e.g. `pass`, `fail`, `none`.","example":"pass"},"size_bytes":{"type":"number","description":"Size of the raw message in bytes.","example":5120},"attachment_count":{"type":"number","description":"Number of attachments.","example":1},"envelope_to":{"type":"string","description":"The SMTP envelope recipient (RCPT TO).","example":"support@in.example.com"},"body_preview":{"type":"string","nullable":true,"description":"First 512 bytes of the plain-text body. Message content, so it is only filled for callers holding `mail.message.body.read`; everyone else gets null. The full message is at `/received/{id}/raw`, behind the same action."},"attachments":{"description":"The email's attachments.","type":"array","items":{"$ref":"#/components/schemas/ReceivedEmailAttachmentDto"}}},"required":["id","mailbox_id","mailbox_address","from","to","cc","subject","rfc822_message_id","received_at","read_at","spam_verdict","spam","spf_result","dkim_result","dmarc_result","size_bytes","attachment_count","envelope_to","body_preview","attachments"],"x-pc-sdk-model":"ReceivedEmailDetail"},"TimelineMetric":{"type":"string","enum":["sent","bounced"]},"TimelinePointDto":{"type":"object","properties":{"date":{"type":"string","description":"UTC date in YYYY-MM-DD format.","example":"2026-04-02"},"count":{"type":"number","description":"Count of messages in this bucket.","example":42}},"required":["date","count"],"x-pc-sdk-model":"TimelinePoint"},"MessageTimelineResponseDto":{"type":"object","properties":{"granularity":{"description":"Bucket size of the series.","allOf":[{"$ref":"#/components/schemas/StatsGranularity"}]},"metric":{"description":"What the series counts.","allOf":[{"$ref":"#/components/schemas/TimelineMetric"}]},"points":{"description":"Dense day-bucketed counts for the requested window. Days with zero messages still appear with `count: 0`.","type":"array","items":{"$ref":"#/components/schemas/TimelinePointDto"}}},"required":["granularity","metric","points"],"x-pc-sdk-model":"MessageTimeline"},"UpsertTemplateDto":{"type":"object","properties":{"name":{"type":"string","description":"Unique template name within the app (lowercase letters, digits, underscore, hyphen)","example":"order-confirmation"},"kind":{"type":"string","description":"Kind: \"template\" (sendable email; default), \"layout\" (chrome wrapper referenced via {{> layout.<name>}}), \"partial\" (reusable block referenced via {{> partial.<name>}}). Cannot be changed after create — delete + recreate to switch kinds.","enum":["template","layout","partial"],"default":"template"},"subject":{"type":"string","description":"Subject line (Handlebars). Layouts and partials ignore this field — they are not standalone-sendable. Pass an empty string for those.","maxLength":255},"body_html":{"type":"string","description":"HTML body (Handlebars)"},"body_text":{"type":"string","description":"Plain-text body (Handlebars). Auto-derived if omitted."},"variables_schema":{"type":"object","additionalProperties":true,"nullable":true,"description":"Declared variable schema. Shape: `{version:1, vars:{<name>:{type, required?, default?, options?}}}`. When set, render + send validate the payload against the schema and 400 with descriptive errors on mismatch."},"tags":{"description":"Workspace-scoped labels for organizing templates. Free-form strings; the editor surfaces existing tags as autocomplete.","type":"array","items":{"type":"string"}}},"required":["name","subject","body_html"]},"TemplateKind":{"type":"string","enum":["template","layout","partial"]},"TemplateSource":{"type":"string","enum":["manual","github"]},"TemplateDto":{"type":"object","properties":{"id":{"type":"string","description":"The template id.","format":"uuid"},"workspace_id":{"type":"string","description":"The workspace that owns the template.","format":"uuid"},"name":{"type":"string","description":"Template name, unique in the workspace; used in send URLs."},"kind":{"description":"What the template is: a sendable `template`, a `layout` that wraps templates, or a `partial` included by them.","allOf":[{"$ref":"#/components/schemas/TemplateKind"}]},"subject":{"type":"string","description":"Subject line (Handlebars)."},"body_html":{"type":"string","description":"HTML body (Handlebars)."},"body_text":{"type":"string","description":"Plain-text body (Handlebars); null to derive it from the HTML.","nullable":true},"variables_schema":{"type":"object","additionalProperties":true,"description":"Declared variable schema (`{ version: 1, vars: { <name>: { type, required?, default?, description?, options? } } }`), as stored; null if not configured.","nullable":true},"tags":{"description":"Tags for organising templates.","type":"array","items":{"type":"string"}},"created_at":{"type":"string","description":"When the template was created.","format":"date-time"},"updated_at":{"type":"string","description":"When the template was last changed.","format":"date-time"},"source":{"description":"Where this row came from. 'manual' for UI-authored, 'github' for rows maintained by the workspace GitHub integration sync. Migration 0020.","default":"manual","allOf":[{"$ref":"#/components/schemas/TemplateSource"}]},"source_ref":{"type":"string","description":"Stable provider pointer used by the editor to build \"Open on GitHub →\" links. Shape: `github:<owner>/<repo>@<branch>:<path-in-repo>`.","nullable":true},"source_synced_at":{"type":"string","description":"When the sync service last wrote this row. null for manual rows.","nullable":true,"format":"date-time"}},"required":["id","workspace_id","name","kind","subject","body_html","body_text","variables_schema","tags","created_at","updated_at","source","source_ref","source_synced_at"],"x-pc-sdk-model":"Template"},"ListTemplatesResponseDto":{"type":"object","properties":{"data":{"description":"The templates on this page.","type":"array","items":{"$ref":"#/components/schemas/TemplateDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListTemplates"},"ListTemplateTagsResponseDto":{"type":"object","properties":{"data":{"description":"Every tag used by a template in the workspace.","type":"array","items":{"type":"string"}}},"required":["data"],"x-pc-sdk-model":"ListTemplateTags"},"RenderTemplateDto":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true,"description":"Data to render into the template. Keys are your variable names and are kept exactly as sent.","example":{"name":"Alice","order_id":"ord_123"}}},"required":["data"]},"RenderedMessageDto":{"type":"object","properties":{"subject":{"type":"string","description":"The rendered subject line."},"html":{"type":"string","description":"Fully-rendered HTML body."},"text":{"type":"string","description":"Plain-text body (derived if not authored)."}},"required":["subject","html","text"],"x-pc-sdk-model":"RenderedMessage"},"PreviewTemplateDto":{"type":"object","properties":{"subject":{"type":"string","description":"Subject template (Handlebars)."},"body_html":{"type":"string","description":"HTML body to render (Handlebars)."},"data":{"type":"object","additionalProperties":true,"description":"Sample data to render variables with. Keys are your variable names and are kept exactly as sent."}},"required":["body_html"]},"LintTemplateDto":{"type":"object","properties":{"subject":{"type":"string","description":"Subject template (Handlebars)."},"body_html":{"type":"string","description":"HTML body to render (Handlebars)."},"data":{"type":"object","additionalProperties":true,"description":"Sample data to render variables with. Keys are your variable names and are kept exactly as sent."}},"required":["body_html"]},"LintSeverity":{"type":"string","enum":["error","warn","info"]},"LintFindingDto":{"type":"object","properties":{"id":{"type":"string","description":"Stable identifier for telemetry / suppressions."},"severity":{"description":"How serious the finding is.","allOf":[{"$ref":"#/components/schemas/LintSeverity"}]},"message":{"type":"string","description":"What is wrong."},"suggestion":{"type":"string","description":"How to fix it, when there is an obvious fix."}},"required":["id","severity","message"],"x-pc-sdk-model":"LintFinding"},"LintResultDto":{"type":"object","properties":{"score":{"type":"number","description":"0-100, higher is better. ≥90 \"looks great\"; <70 \"likely to spam-folder\"."},"findings":{"description":"Every problem found, most severe first.","type":"array","items":{"$ref":"#/components/schemas/LintFindingDto"}}},"required":["score","findings"],"x-pc-sdk-model":"LintResult"},"TemplateVariablesResponseDto":{"type":"object","properties":{"data":{"description":"Variables auto-detected from the saved template body + subject (Handlebars expressions, dotted paths preserved).","type":"array","items":{"type":"string"}}},"required":["data"],"x-pc-sdk-model":"TemplateVariables"},"TestSendTemplateDto":{"type":"object","properties":{"from":{"type":"string","description":"Sender. Either a bare address (`hello@acme.com`) or a display name plus the address in angle brackets (`Acme <hello@acme.com>`; quote a name that contains a comma: `\"Acme, Inc.\" <hello@acme.com>`). The display name is at most 200 characters. The address's domain must itself be an active (verified) sending domain of the workspace; a verified subdomain does not cover its parent (with only `mail.acme.com` verified, `hello@acme.com` is refused with 422 `from_domain_not_verified`). Same rules as a normal send.","example":"Acme <hello@acme.com>"},"to":{"type":"string","description":"Recipient address for the test email. Suppression-list and rate-limit checks are bypassed for test sends, so a recently-bounced address is still reachable for QA.","format":"email"},"data":{"type":"object","additionalProperties":true,"description":"Variable values to render into the template. Keys correspond to the dotted paths returned by the /variables endpoint.","example":{"name":"Alice","code":"123456"}}},"required":["from","to"]},"SendAcceptedDto":{"type":"object","properties":{"id":{"type":"string","description":"Id of the stored message (`outbound_message.id`). Pass it to `GET /messages/{id}` and match it against `data.email_id` on webhook events. Null only if the message log write failed; the send itself was still queued.","format":"uuid","nullable":true,"example":"4f8b2c1e-9a3d-4e57-b6f0-2d1c8e7a9b05"},"accepted":{"type":"boolean","description":"Always true on a 202.","example":true},"from":{"type":"string","description":"The From field as sent, display name included.","example":"Acme <hello@acme.com>"},"to":{"description":"The `to` field as sent: one address, or the array.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"}}],"example":"user@example.com"},"subject":{"type":"string","description":"The rendered subject line."},"email_id":{"type":"string","description":"The email this send created (`GET /emails/{id}`): one email, one message per recipient. Equals `id` for a send whose first message was recorded.","format":"uuid","example":"4f8b2c1e-9a3d-4e57-b6f0-2d1c8e7a9b05"}},"required":["id","accepted","from","to","subject","email_id"],"x-pc-sdk-model":"SendAccepted"},"SendTemplateDto":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true,"description":"Data to render into the template. Keys are your variable names and are kept exactly as sent.","example":{"name":"Alice","order_id":"ord_123"}},"from":{"type":"string","description":"Sender. Either a bare address (`hello@acme.com`) or a display name plus the address in angle brackets (`Acme <hello@acme.com>`; quote a name that contains a comma: `\"Acme, Inc.\" <hello@acme.com>`). The display name is at most 200 characters. The address's domain must itself be an active (verified) sending domain of the workspace; a verified subdomain does not cover its parent (with only `mail.acme.com` verified, `hello@acme.com` is refused with 422 `from_domain_not_verified`). Optional: omit it to send from the workspace default sender (`GET /v1/workspaces/{id}/sending-defaults`); with no default set the send is refused with 422 `no_default_sender`.","example":"Acme <hello@acme.com>"},"to":{"description":"Recipient: one address, or an array of up to 50 (tasks/mail-api/002). Each recipient gets its own copy (its own suppression check, message row and delivery status) showing the full `To` list. One address is the historical shape and behaves exactly as before.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":"user@example.com"},"cc":{"description":"Cc recipients: one address or an array. Shown in the `Cc` header to every recipient.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["finance@example.com"]},"bcc":{"description":"Bcc recipients: one address or an array. Each gets the message; no header names them.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["audit@example.com"]},"reply_to":{"description":"Reply-To address(es): one address or an array. This is the only way to set `Reply-To`.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":"support@acme.com"},"headers":{"type":"object","description":"Custom headers, as a map of header name to value, kept exactly as sent. Allowed: `X-*` (except `X-SES-*`), `List-Unsubscribe`, `List-Unsubscribe-Post`, `List-Id`, `In-Reply-To` and `References`; at most 50, values up to 998 characters with no line breaks. Any other header (`From`, `To`, `Cc`, `Bcc`, `Subject`, `Date`, `Message-ID`, `DKIM-Signature`, `Return-Path`, `Reply-To`, …) is a 400 `MAIL_HEADER_NOT_ALLOWED`: use the matching field (`reply_to` for `Reply-To`).","additionalProperties":{"type":"string"},"example":{"x-entity-ref-id":"order-1234"}},"tags":{"description":"Up to 10 `{ name, value }` labels, stored on every message of the send. Filter sends by them with `GET /emails?tag[name]=value`.","maxItems":10,"example":[{"name":"category","value":"confirm_email"}],"type":"array","items":{"$ref":"#/components/schemas/EmailTagDto"}},"subject":{"type":"string","description":"Subject override (optional; uses template subject otherwise)"},"topic_id":{"type":"string","description":"Send as mail on this topic (tasks/mail-api/016). The recipient must be a contact subscribed to the topic: one who opted in, or, for a topic whose `default_subscription` is `opt_in`, one with a recorded consent who has not opted out. Anyone else is refused with 422 `RECIPIENT_SUPPRESSED` and `details.reason` `unsubscribe` (opted out of the topic or unsubscribed from everything) or `no_consent` (never opted in, or not a contact), and an `email.suppressed` event. A topic send carries a one-click unsubscribe link (`{{{unsubscribe_url}}}` in the template) and the `List-Unsubscribe` + `List-Unsubscribe-Post` headers, and goes out on the separate marketing stream. A `topic_id` that is not a topic of this workspace is a 422 `TOPIC_NOT_FOUND`.","format":"uuid","example":"3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c"}},"required":["data","to"]},"SendBatchRowDto":{"type":"object","properties":{"from":{"type":"string","description":"Sender. Either a bare address (`hello@acme.com`) or a display name plus the address in angle brackets (`Acme <hello@acme.com>`; quote a name that contains a comma: `\"Acme, Inc.\" <hello@acme.com>`). The display name is at most 200 characters. The address's domain must itself be an active (verified) sending domain of the workspace; a verified subdomain does not cover its parent (with only `mail.acme.com` verified, `hello@acme.com` is refused with 422 `from_domain_not_verified`).","example":"Acme <noreply@acme.com>"},"to":{"description":"Recipient: one address, or an array of up to 50 (one row, one message per recipient).","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":"alice@example.com"},"cc":{"description":"Cc recipients: one address or an array. Shown in the `Cc` header to every recipient.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["finance@example.com"]},"bcc":{"description":"Bcc recipients: one address or an array. Each gets the message; no header names them.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["audit@example.com"]},"reply_to":{"description":"Reply-To address(es): one address or an array. This is the only way to set `Reply-To`.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":"support@acme.com"},"headers":{"type":"object","description":"Custom headers, as a map of header name to value, kept exactly as sent. Allowed: `X-*` (except `X-SES-*`), `List-Unsubscribe`, `List-Unsubscribe-Post`, `List-Id`, `In-Reply-To` and `References`; at most 50, values up to 998 characters with no line breaks. Any other header (`From`, `To`, `Cc`, `Bcc`, `Subject`, `Date`, `Message-ID`, `DKIM-Signature`, `Return-Path`, `Reply-To`, …) is a 400 `MAIL_HEADER_NOT_ALLOWED`: use the matching field (`reply_to` for `Reply-To`).","additionalProperties":{"type":"string"},"example":{"x-entity-ref-id":"order-1234"}},"tags":{"description":"Up to 10 `{ name, value }` labels, stored on every message of the send. Filter sends by them with `GET /emails?tag[name]=value`.","maxItems":10,"example":[{"name":"category","value":"confirm_email"}],"type":"array","items":{"$ref":"#/components/schemas/EmailTagDto"}},"subject":{"type":"string","description":"Optional override for the rendered subject. Falls back to the template subject.","maxLength":998},"data":{"type":"object","additionalProperties":true,"description":"Template data passed into the Handlebars render. Keys are kept exactly as sent.","example":{"name":"Alice","code":"A1B2C3"}},"topic_id":{"type":"string","description":"Send as mail on this topic (tasks/mail-api/016). The recipient must be a contact subscribed to the topic: one who opted in, or, for a topic whose `default_subscription` is `opt_in`, one with a recorded consent who has not opted out. Anyone else is refused with 422 `RECIPIENT_SUPPRESSED` and `details.reason` `unsubscribe` (opted out of the topic or unsubscribed from everything) or `no_consent` (never opted in, or not a contact), and an `email.suppressed` event. A topic send carries a one-click unsubscribe link (`{{{unsubscribe_url}}}` in the template) and the `List-Unsubscribe` + `List-Unsubscribe-Post` headers, and goes out on the separate marketing stream. A `topic_id` that is not a topic of this workspace is a 422 `TOPIC_NOT_FOUND`. In a batch, a refused row is `rejected` with that code; the other rows are unaffected.","format":"uuid","example":"3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c"},"idempotency_key":{"type":"string","description":"Optional per-row idempotency key. Same dedupe namespace as the `Idempotency-Key` request header.","maxLength":256}},"required":["from","to","data"]},"SendBatchDto":{"type":"object","properties":{"messages":{"description":"Up to 100 messages to render and enqueue in a single call. Each is processed independently — partial successes are allowed.","minItems":1,"maxItems":100,"type":"array","items":{"$ref":"#/components/schemas/SendBatchRowDto"}}},"required":["messages"]},"SendBatchRowState":{"type":"string","enum":["accepted","rejected"]},"SendBatchRowErrorDto":{"type":"object","properties":{"code":{"type":"string","description":"Error code for the rejected row."},"message":{"type":"string","description":"Why the row was rejected."}},"required":["code","message"],"x-pc-sdk-model":"SendBatchRowError"},"SendBatchRowStatusDto":{"type":"object","properties":{"index":{"type":"number","description":"Index into the request `messages[]` array."},"id":{"type":"string","description":"Id of the stored message when accepted (`outbound_message.id`, the same id `GET /messages/{id}` and webhook events use); absent on reject. Null only if the message log write failed; the send itself was still queued.","format":"uuid","nullable":true},"status":{"description":"Whether the row was accepted for sending or rejected.","allOf":[{"$ref":"#/components/schemas/SendBatchRowState"}]},"error":{"description":"Why the row was rejected; absent when accepted.","nullable":true,"allOf":[{"$ref":"#/components/schemas/SendBatchRowErrorDto"}]}},"required":["index","status"],"x-pc-sdk-model":"SendBatchRowStatus"},"SendBatchSummaryDto":{"type":"object","properties":{"accepted":{"type":"number","description":"Rows accepted for sending."},"rejected":{"type":"number","description":"Rows rejected."}},"required":["accepted","rejected"],"x-pc-sdk-model":"SendBatchSummary"},"SendBatchOpenApiResponseDto":{"type":"object","properties":{"data":{"description":"One status per row, in request order.","type":"array","items":{"$ref":"#/components/schemas/SendBatchRowStatusDto"}},"summary":{"$ref":"#/components/schemas/SendBatchSummaryDto"}},"required":["data","summary"],"x-pc-sdk-model":"SendBatchOpenApi"},"DomainTestSendDto":{"type":"object","properties":{"from":{"type":"string","description":"Sender. Either a bare address (`hello@acme.com`) or a display name plus the address in angle brackets (`Acme <hello@acme.com>`; quote a name that contains a comma: `\"Acme, Inc.\" <hello@acme.com>`). The display name is at most 200 characters. The address's domain must itself be an active (verified) sending domain of the workspace; a verified subdomain does not cover its parent (with only `mail.acme.com` verified, `hello@acme.com` is refused with 422 `from_domain_not_verified`). Must be an address at this exact domain. Defaults to `test@<domain>`.","example":"Acme <hello@acme.com>"},"to":{"type":"string","description":"Recipient of the test email. The suppression list is not checked for test sends; they count against the workspace test-send limit (30 per hour) instead of the send limits.","format":"email","example":"you@acme.com"}},"required":["to"]},"CreateContactImportDto":{"type":"object","properties":{"csv":{"type":"string","description":"The CSV file content, UTF-8, at most 10 MB and 100,000 rows. The first line is a header with an `email` column. Optional columns: `first_name`, `last_name`, `unsubscribed` (true/false), `consent` (true/false), `consented_at` (ISO 8601), `consent_source`, and any defined contact property key. Headers are case-insensitive (`First Name` works). Other columns are ignored and reported. A row is consented only when it says so (`consent` true, or a `consented_at` date); every other imported contact starts without consent and receives only topics it later opts in to.","example":"email,first_name,consent,consented_at\nada@example.com,Ada,true,2026-10-01T09:00:00Z\n"},"on_conflict":{"type":"string","description":"`upsert` updates an existing contact (provided fields; properties merge); `skip` leaves existing contacts unchanged. Either way an import never re-subscribes a contact that unsubscribed and never overrides a topic opt-out.","enum":["upsert","skip"]},"consent_source":{"type":"string","description":"Recorded as `consent_source` on consented rows that have no `consent_source` column value. Defaults to `import`.","maxLength":255,"example":"webinar-2026-10"},"topic_ids":{"description":"Opt the consented rows in to these topics (existing opt-outs win).","maxItems":20,"type":"array","items":{"type":"string","format":"uuid"}},"filename":{"type":"string","description":"The file name, for display.","maxLength":255,"example":"newsletter.csv"}},"required":["csv","on_conflict"]},"ContactImportStatus":{"type":"string","enum":["queued","processing","completed","failed"]},"ContactImportConflictMode":{"type":"string","enum":["upsert","skip"]},"ContactImportErrorDto":{"type":"object","properties":{"line":{"type":"number","description":"Line in the file (1 is the header)."},"error":{"type":"string","description":"Why the row was skipped.","example":"invalid or missing email"}},"required":["line","error"],"x-pc-sdk-model":"ContactImportError"},"ContactImportDto":{"type":"object","properties":{"id":{"type":"string","description":"The import id.","format":"uuid"},"status":{"description":"Where the import is: `queued`, `processing`, then `completed` or `failed`.","allOf":[{"$ref":"#/components/schemas/ContactImportStatus"}]},"on_conflict":{"description":"What happens to a row whose email is already a contact: `upsert` updates it, `skip` leaves it.","allOf":[{"$ref":"#/components/schemas/ContactImportConflictMode"}]},"filename":{"type":"string","description":"The uploaded file's name, if one was given.","nullable":true},"size_bytes":{"type":"number","description":"Size of the uploaded CSV in bytes."},"consent_source":{"type":"string","description":"Where the consent for these contacts came from, stored on every imported contact.","nullable":true},"topic_ids":{"description":"Topics every imported contact was subscribed to.","type":"array","items":{"type":"string","format":"uuid"}},"total_rows":{"type":"number","description":"Data rows in the file (header excluded); 0 until processing starts."},"processed_rows":{"type":"number","description":"Rows processed so far."},"created_count":{"type":"number","description":"Rows that created a new contact."},"updated_count":{"type":"number","description":"Rows that updated an existing contact."},"skipped_count":{"type":"number","description":"Existing contacts left alone (`skip`), and duplicate rows."},"error_count":{"type":"number","description":"Rows that could not be imported."},"consented_count":{"type":"number","description":"Rows that asserted consent."},"errors":{"description":"The first 100 problems, with line numbers.","type":"array","items":{"$ref":"#/components/schemas/ContactImportErrorDto"}},"failure_reason":{"type":"string","nullable":true,"description":"Why a `failed` import stopped."},"created_at":{"type":"string","description":"When the import was submitted.","format":"date-time"},"started_at":{"type":"string","description":"When processing started; null while `queued`.","format":"date-time","nullable":true},"completed_at":{"type":"string","description":"When processing finished; null until then.","format":"date-time","nullable":true}},"required":["id","status","on_conflict","filename","size_bytes","consent_source","topic_ids","total_rows","processed_rows","created_count","updated_count","skipped_count","error_count","consented_count","errors","failure_reason","created_at","started_at","completed_at"],"x-pc-sdk-model":"ContactImport"},"ListContactImportsResponseDto":{"type":"object","properties":{"data":{"description":"The imports on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/ContactImportDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListContactImports"},"ConsentDto":{"type":"object","properties":{"source":{"type":"string","description":"Where the consent came from, for your records and for an audit: a form name, a checkout checkbox, a double opt-in confirmation.","maxLength":255,"example":"signup-form-2026"},"consented_at":{"type":"string","description":"When the consent was given. Defaults to now.","format":"date-time","example":"2026-10-24T09:00:00Z"}},"required":["source"]},"TopicSubscriptionInputDto":{"type":"object","properties":{"id":{"type":"string","description":"Topic id.","format":"uuid"},"subscription":{"type":"string","description":"`opt_in` subscribes the contact to the topic; `opt_out` unsubscribes it.","enum":["opt_in","opt_out"]}},"required":["id","subscription"]},"CreateContactDto":{"type":"object","properties":{"email":{"type":"string","description":"Unique per workspace; stored lowercased.","format":"email","example":"ada@example.com"},"first_name":{"type":"string","description":"The contact's first name, available as `{{first_name}}` in templates.","maxLength":255,"nullable":true,"example":"Ada"},"last_name":{"type":"string","description":"The contact's last name, available as `{{last_name}}` in templates.","maxLength":255,"nullable":true,"example":"Lovelace"},"unsubscribed":{"type":"boolean","description":"Global unsubscribe: the contact receives no topic mail and no mail with an unsubscribe link. Transactional mail is unaffected.","default":false},"properties":{"type":"object","description":"Custom properties, keyed by a defined contact property (`POST /contact-properties`). Values must match its type.","additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"}]},"example":{"company":"Acme","seats":12}},"consent":{"description":"A marketing consent the contact gave you. Without one, the contact receives only topics it explicitly opted in to (`topics`, or `PATCH .../topics`).","nullable":true,"allOf":[{"$ref":"#/components/schemas/ConsentDto"}]},"topics":{"description":"Initial topic subscriptions.","maxItems":50,"type":"array","items":{"$ref":"#/components/schemas/TopicSubscriptionInputDto"}}},"required":["email"]},"ContactCreatedVia":{"type":"string","enum":["api","dashboard","import","unsubscribe"]},"ContactDto":{"type":"object","properties":{"id":{"type":"string","description":"The contact id.","format":"uuid"},"email":{"type":"string","description":"The contact's email address, unique within the workspace.","format":"email","example":"ada@example.com"},"first_name":{"type":"string","description":"The contact's first name.","nullable":true},"last_name":{"type":"string","description":"The contact's last name.","nullable":true},"unsubscribed":{"type":"boolean","description":"Global unsubscribe."},"unsubscribed_at":{"type":"string","description":"When the contact unsubscribed from all mail; null while subscribed.","format":"date-time","nullable":true},"properties":{"type":"object","description":"Custom property values keyed by contact-property key.","additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"}]},"example":{"company":"Acme"}},"consented_at":{"type":"string","description":"When marketing consent was recorded; null when none was.","format":"date-time","nullable":true},"consent_source":{"type":"string","description":"Where the consent to email this contact came from (free text, for your records).","nullable":true,"example":"signup-form-2026"},"created_via":{"description":"How the contact was added.","allOf":[{"$ref":"#/components/schemas/ContactCreatedVia"}]},"created_at":{"type":"string","description":"When the contact was created.","format":"date-time"},"updated_at":{"type":"string","description":"When the contact was last changed.","format":"date-time"}},"required":["id","email","first_name","last_name","unsubscribed","unsubscribed_at","properties","consented_at","consent_source","created_via","created_at","updated_at"],"x-pc-sdk-model":"Contact"},"ListContactsResponseDto":{"type":"object","properties":{"data":{"description":"The contacts on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/ContactDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListContacts"},"UpdateContactDto":{"type":"object","properties":{"first_name":{"type":"string","description":"New first name; null clears it.","maxLength":255,"nullable":true},"last_name":{"type":"string","description":"New last name; null clears it.","maxLength":255,"nullable":true},"unsubscribed":{"type":"boolean","description":"Set or clear the global unsubscribe."},"properties":{"type":"object","description":"Merged into the stored properties; a `null` value removes that key.","additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"}],"nullable":true}},"consent":{"description":"Record a consent, or `null` to withdraw it.","nullable":true,"allOf":[{"$ref":"#/components/schemas/ConsentDto"}]}}},"Subscription":{"type":"string","enum":["opt_in","opt_out"]},"TopicVisibility":{"type":"string","enum":["public","private"]},"SubscriptionReason":{"type":"string","enum":["opted_in","default_with_consent","unsubscribed","opted_out","no_consent","not_opted_in"]},"ContactTopicDto":{"type":"object","properties":{"id":{"type":"string","description":"The topic id.","format":"uuid"},"name":{"type":"string","description":"Display name of the topic, shown on the unsubscribe page."},"description":{"type":"string","description":"Optional longer text shown under the name on the unsubscribe page.","nullable":true},"default_subscription":{"description":"Whether a contact who never chose is subscribed (`opt_in`) or not (`opt_out`).","allOf":[{"$ref":"#/components/schemas/Subscription"}]},"visibility":{"description":"`public` topics appear on the unsubscribe page; `private` ones do not.","allOf":[{"$ref":"#/components/schemas/TopicVisibility"}]},"subscription":{"description":"The contact's own choice; null when it never made one.","nullable":true,"allOf":[{"$ref":"#/components/schemas/Subscription"}]},"subscribed":{"type":"boolean","description":"Whether a send on this topic would reach the contact now."},"reason":{"description":"Why: `opted_in`, `default_with_consent`, or, when not subscribed, `unsubscribed` (global), `opted_out`, `no_consent` (an `opt_in` topic but no recorded consent), `not_opted_in` (an `opt_out` topic).","allOf":[{"$ref":"#/components/schemas/SubscriptionReason"}]}},"required":["id","name","description","default_subscription","visibility","subscription","subscribed","reason"],"x-pc-sdk-model":"ContactTopic"},"ContactTopicsResponseDto":{"type":"object","properties":{"contact_id":{"type":"string","description":"The contact these subscriptions belong to.","format":"uuid"},"data":{"description":"Every topic of the workspace with this contact's subscription to it.","type":"array","items":{"$ref":"#/components/schemas/ContactTopicDto"}}},"required":["contact_id","data"],"x-pc-sdk-model":"ContactTopics"},"UpdateContactTopicsDto":{"type":"object","properties":{"topics":{"description":"The topics to change, each with its new subscription.","minItems":1,"maxItems":50,"type":"array","items":{"$ref":"#/components/schemas/TopicSubscriptionInputDto"}}},"required":["topics"]},"SegmentType":{"type":"string","enum":["static","rule"]},"SegmentMatch":{"type":"string","enum":["all","any"]},"SegmentOperator":{"type":"string","enum":["equals","contains","exists"]},"SegmentConditionDto":{"type":"object","properties":{"field":{"type":"string","description":"What to test: a contact field (`email`, `first_name`, `last_name`) or the key of a defined contact property.","pattern":"^[a-z][a-z0-9_]{0,49}$","example":"plan"},"operator":{"description":"`equals`: case-insensitive equality (numeric for a `number` property). `contains`: case-insensitive substring (string fields only). `exists`: the field has a non-empty value; takes no `value`.","allOf":[{"$ref":"#/components/schemas/SegmentOperator"}]},"value":{"description":"The value to compare with. Required for `equals` and `contains`; a number for a `number` property.","oneOf":[{"type":"string","maxLength":500},{"type":"number"}],"example":"pro"}},"required":["field","operator"],"x-pc-sdk-model":"SegmentCondition"},"SegmentRuleDto":{"type":"object","properties":{"match":{"description":"`all`: every condition must hold (AND). `any`: at least one (OR).","allOf":[{"$ref":"#/components/schemas/SegmentMatch"}]},"conditions":{"description":"The conditions; a contact matches when it meets all of them.","minItems":1,"maxItems":20,"type":"array","items":{"$ref":"#/components/schemas/SegmentConditionDto"}}},"required":["match","conditions"],"x-pc-sdk-model":"SegmentRule"},"SegmentDto":{"type":"object","properties":{"id":{"type":"string","description":"The segment id.","format":"uuid"},"name":{"type":"string","description":"Name of the segment.","example":"Pro customers"},"description":{"type":"string","description":"Optional description of who is in the segment.","nullable":true},"type":{"description":"`static`: an explicit member list. `rule`: the contacts matching `rule`.","allOf":[{"$ref":"#/components/schemas/SegmentType"}]},"rule":{"nullable":true,"description":"Null for a static segment.","allOf":[{"$ref":"#/components/schemas/SegmentRuleDto"}]},"created_at":{"type":"string","description":"When the segment was created.","format":"date-time"},"updated_at":{"type":"string","description":"When the segment was last changed.","format":"date-time"}},"required":["id","name","description","type","rule","created_at","updated_at"],"x-pc-sdk-model":"Segment"},"ContactSegmentsResponseDto":{"type":"object","properties":{"contact_id":{"type":"string","description":"The contact whose segments these are.","format":"uuid"},"data":{"description":"Every segment the contact is in now (static ones it was added to, rule ones it matches), oldest segment first. At most 100: one page.","type":"array","items":{"$ref":"#/components/schemas/SegmentDto"}}},"required":["contact_id","data"],"x-pc-sdk-model":"ContactSegments"},"SegmentMembershipDto":{"type":"object","properties":{"segment_id":{"type":"string","description":"The segment the contact was added to.","format":"uuid"},"contact_id":{"type":"string","description":"The contact that was added.","format":"uuid"},"added_at":{"type":"string","format":"date-time","description":"When the contact was added (the first time, if it was added twice)."}},"required":["segment_id","contact_id","added_at"],"x-pc-sdk-model":"SegmentMembership"},"CreateContactPropertyDto":{"type":"object","properties":{"key":{"type":"string","description":"The property key: lowercase letters, digits and underscores, starting with a letter, up to 50 characters. Use it as a CSV column header and as a key of `properties` on a contact. Contact fields (`email`, `first_name`, …) are reserved.","pattern":"^[a-z][a-z0-9_]{0,49}$","example":"company"},"type":{"type":"string","description":"Value type. Fixed once created.","enum":["string","number"]},"fallback_value":{"description":"The value to use when a contact has none. Must match `type`.","oneOf":[{"type":"string","maxLength":500},{"type":"number"}],"nullable":true,"example":"Acme"}},"required":["key","type"]},"ContactPropertyType":{"type":"string","enum":["string","number"]},"ContactPropertyDto":{"type":"object","properties":{"id":{"type":"string","description":"The property id.","format":"uuid"},"key":{"type":"string","description":"The key used in contact `properties` and as `{{key}}` in templates.","example":"company"},"type":{"description":"The value type: `string` or `number`.","allOf":[{"$ref":"#/components/schemas/ContactPropertyType"}]},"fallback_value":{"description":"Value used for a contact that has no value for this property; null for none.","oneOf":[{"type":"string"},{"type":"number"}],"nullable":true},"created_at":{"type":"string","description":"When the property was created.","format":"date-time"},"updated_at":{"type":"string","description":"When the property was last changed.","format":"date-time"}},"required":["id","key","type","fallback_value","created_at","updated_at"],"x-pc-sdk-model":"ContactProperty"},"ListContactPropertiesResponseDto":{"type":"object","properties":{"data":{"description":"The contact properties on this page.","type":"array","items":{"$ref":"#/components/schemas/ContactPropertyDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListContactProperties"},"UpdateContactPropertyDto":{"type":"object","properties":{"fallback_value":{"description":"The new fallback value (null clears it). The key and type cannot change.","oneOf":[{"type":"string","maxLength":500},{"type":"number"}],"nullable":true}}},"CreateTopicDto":{"type":"object","properties":{"name":{"type":"string","description":"Shown to recipients on the unsubscribe page.","maxLength":50,"example":"Product updates"},"description":{"type":"string","description":"One line under the name on the unsubscribe page.","maxLength":200,"nullable":true},"default_subscription":{"type":"string","description":"`opt_in`: contacts receive the topic unless they opt out — but only contacts with a recorded consent (`consent` on the contact, or an import row that asserted it). `opt_out`: contacts receive it only after opting in. Fixed once created.","enum":["opt_in","opt_out"]},"visibility":{"type":"string","description":"`public` topics are listed on the unsubscribe page; `private` ones are not (a recipient can still leave one from its own link).","enum":["public","private"],"default":"public"}},"required":["name","default_subscription"]},"TopicDto":{"type":"object","properties":{"id":{"type":"string","description":"The topic id.","format":"uuid"},"name":{"type":"string","description":"Display name of the topic, shown on the unsubscribe page.","example":"Product updates"},"description":{"type":"string","description":"Optional longer text shown under the name on the unsubscribe page.","nullable":true},"default_subscription":{"description":"Whether a contact who never chose is subscribed (`opt_in`) or not (`opt_out`).","allOf":[{"$ref":"#/components/schemas/Subscription"}]},"visibility":{"description":"`public` topics appear on the unsubscribe page; `private` ones do not.","allOf":[{"$ref":"#/components/schemas/TopicVisibility"}]},"created_at":{"type":"string","description":"When the topic was created.","format":"date-time"},"updated_at":{"type":"string","description":"When the topic was last changed.","format":"date-time"}},"required":["id","name","description","default_subscription","visibility","created_at","updated_at"],"x-pc-sdk-model":"Topic"},"ListTopicsResponseDto":{"type":"object","properties":{"data":{"description":"The topics on this page.","type":"array","items":{"$ref":"#/components/schemas/TopicDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListTopics"},"UpdateTopicDto":{"type":"object","properties":{"name":{"type":"string","description":"New display name of the topic.","maxLength":50},"description":{"type":"string","description":"New description; null clears it.","maxLength":200,"nullable":true},"visibility":{"type":"string","description":"New visibility: `public` topics appear on the unsubscribe page, `private` ones do not.","enum":["public","private"]}}},"CreateSegmentDto":{"type":"object","properties":{"name":{"type":"string","description":"Unique per workspace.","minLength":1,"maxLength":100,"example":"Pro customers"},"description":{"type":"string","description":"Optional description of who is in the segment.","maxLength":300,"nullable":true,"example":"Everyone on the pro plan"},"rule":{"description":"Omit for a static segment (add contacts with `POST .../contacts/{contact}/segments/{segment_id}`). Set it for a rule segment: its members are the contacts that match, evaluated whenever the segment is read. The type is fixed once created.","nullable":true,"allOf":[{"$ref":"#/components/schemas/SegmentRuleDto"}]}},"required":["name"]},"PreviewSegmentDto":{"type":"object","properties":{"rule":{"$ref":"#/components/schemas/SegmentRuleDto"}},"required":["rule"]},"SegmentMetricsDto":{"type":"object","properties":{"segment_id":{"type":"string","format":"uuid","nullable":true,"description":"Null on a preview."},"contact_count":{"type":"number","description":"Contacts in the segment now.","example":1240},"unsubscribed_count":{"type":"number","description":"Of those, globally unsubscribed.","example":31},"unsubscribed_share":{"type":"number","description":"`unsubscribed_count / contact_count`, 0 to 1 (4 decimals); 0 for an empty segment.","example":0.025},"consented_count":{"type":"number","description":"Of those, with a recorded marketing consent.","example":1100},"computed_at":{"type":"string","format":"date-time","description":"When the counts were taken (rule segments change as contacts do)."}},"required":["segment_id","contact_count","unsubscribed_count","unsubscribed_share","consented_count","computed_at"],"x-pc-sdk-model":"SegmentMetrics"},"SegmentPreviewDto":{"type":"object","properties":{"metrics":{"$ref":"#/components/schemas/SegmentMetricsDto"},"sample":{"description":"Up to 5 matching contacts, newest first.","type":"array","items":{"$ref":"#/components/schemas/ContactDto"}}},"required":["metrics","sample"],"x-pc-sdk-model":"SegmentPreview"},"ListSegmentsResponseDto":{"type":"object","properties":{"data":{"description":"The segments on this page.","type":"array","items":{"$ref":"#/components/schemas/SegmentDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListSegments"},"UpdateSegmentDto":{"type":"object","properties":{"name":{"type":"string","description":"New name of the segment.","minLength":1,"maxLength":100},"description":{"type":"string","description":"New description; null clears it.","maxLength":300,"nullable":true},"rule":{"description":"A new rule (rule segments only; a static segment cannot take one).","allOf":[{"$ref":"#/components/schemas/SegmentRuleDto"}]}}},"ListSegmentContactsResponseDto":{"type":"object","properties":{"data":{"description":"The contacts in the segment on this page.","type":"array","items":{"$ref":"#/components/schemas/ContactDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListSegmentContacts"},"SenderDomainStatus":{"type":"string","enum":["not_started","pending","partially_verified","verified","temporary_failure","failed","disabled","deleted","not_found"]},"DefaultSenderDto":{"type":"object","properties":{"address":{"type":"string","description":"The default From: a bare address (`hello@acme.com`) or a display name plus the address (`Acme <hello@acme.com>`). Template sends with no `from` go out with it.","example":"Acme <hello@acme.com>"},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The workspace domain the address is on; null when that domain was deleted after the default was set.","example":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b"},"domain_status":{"description":"The domain's live `verification_status` (the same value `GET /v1/workspaces/{id}/domains/{domainId}` returns), or `deleted` when the domain was removed. The shared `SenderDomainStatus` enum, which Auth and Waitlist use too; Mail never answers `not_found` here.","example":"verified","allOf":[{"$ref":"#/components/schemas/SenderDomainStatus"}]},"verified":{"type":"boolean","description":"Whether mail from this address sends right now: the domain is `verified`, or `temporary_failure` (a record went missing within the 72 h grace). When false, sends that use the default are refused with 422 `from_domain_not_verified` or `domain_not_verified_by_provider`.","example":true}},"required":["address","domain_id","domain_status","verified"],"x-pc-sdk-model":"DefaultSender"},"DefaultSenderSkippedSendsDto":{"type":"object","properties":{"count":{"type":"integer","minimum":0,"example":0,"description":"Template sends skipped since the setting last changed because they named no `from` and no default sender was set. Reset to 0 by every PUT."},"last_at":{"type":"string","format":"date-time","nullable":true,"description":"When the most recent skip happened; null when none ever did.","example":null},"last_template":{"type":"string","nullable":true,"description":"The template of the most recent skipped send.","example":null}},"required":["count","last_at","last_template"],"x-pc-sdk-model":"DefaultSenderSkippedSends"},"SendingDefaultsDto":{"type":"object","properties":{"default_sender":{"nullable":true,"description":"The workspace default sender, or null when none is set. With none set, a template send with no `from` is skipped: the HTTP route answers 422 `no_default_sender`, and an `email.skipped` webhook event is logged.","allOf":[{"$ref":"#/components/schemas/DefaultSenderDto"}]},"skipped_sends":{"description":"Sends skipped for want of a sender (`no_default_sender`). A non-zero `count` means some product emails did not go out: set a default sender.","allOf":[{"$ref":"#/components/schemas/DefaultSenderSkippedSendsDto"}]},"updated_at":{"type":"string","format":"date-time","nullable":true,"description":"When the settings last changed (set, cleared, or first created by a skipped send); null when there are none.","example":"2026-10-17T09:30:00.000Z"}},"required":["default_sender","skipped_sends","updated_at"],"x-pc-sdk-model":"SendingDefaults"},"PutSendingDefaultsDto":{"type":"object","properties":{"address":{"type":"string","nullable":true,"description":"The new default From, or null to clear it. A bare address or `Name <address>` (display name up to 200 characters). Its domain must be a sending domain of this workspace (it may still be pending verification; `verified` in the response says whether it sends yet).","example":"Acme <hello@acme.com>"}},"required":["address"]},"EmailTemplateRefDto":{"type":"object","properties":{"name":{"type":"string","description":"Name of a saved template of this workspace.","example":"welcome"},"data":{"type":"object","description":"Data rendered into the template (Handlebars). Keys are kept exactly as sent.","additionalProperties":true,"example":{"first_name":"Ada"}}},"required":["name"]},"SendEmailDto":{"type":"object","properties":{"from":{"type":"string","description":"Sender. Either a bare address (`hello@acme.com`) or a display name plus the address in angle brackets (`Acme <hello@acme.com>`; quote a name that contains a comma: `\"Acme, Inc.\" <hello@acme.com>`). The display name is at most 200 characters. The address's domain must itself be an active (verified) sending domain of the workspace; a verified subdomain does not cover its parent (with only `mail.acme.com` verified, `hello@acme.com` is refused with 422 `from_domain_not_verified`).","example":"Acme <hello@mail.acme.com>"},"to":{"description":"Recipient: one address, or an array. At most 50 distinct recipients across `to`, `cc` and `bcc` (400 `RECIPIENT_LIMIT`). Each recipient gets its own copy, with its own suppression check, message (`GET /messages`) and delivery status, showing the full `To` and `Cc` lists.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["success@simulator.amazonses.com"]},"cc":{"description":"Cc recipients: one address or an array. Shown in the `Cc` header to every recipient.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["finance@example.com"]},"bcc":{"description":"Bcc recipients: one address or an array. Each gets the message; no header names them.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["audit@example.com"]},"reply_to":{"description":"Reply-To address(es): one address or an array. This is the only way to set `Reply-To`.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":"support@acme.com"},"subject":{"type":"string","description":"Subject line. Required with `html`/`text`; with a `template` it overrides the template's subject.","maxLength":998,"example":"Your order has shipped"},"html":{"type":"string","description":"HTML body, sent exactly as given (no templating). With no `text`, the plain-text part is derived from it.","maxLength":512000,"example":"<p>Your order has shipped.</p>"},"text":{"type":"string","description":"Plain-text body, sent exactly as given.","maxLength":512000,"example":"Your order has shipped."},"template":{"description":"Send a saved template instead of `html`/`text` (400 `EMAIL_CONTENT_CONFLICT` with both, or with neither).","allOf":[{"$ref":"#/components/schemas/EmailTemplateRefDto"}]},"headers":{"type":"object","description":"Custom headers, as a map of header name to value, kept exactly as sent. Allowed: `X-*` (except `X-SES-*`), `List-Unsubscribe`, `List-Unsubscribe-Post`, `List-Id`, `In-Reply-To` and `References`; at most 50, values up to 998 characters with no line breaks. Any other header (`From`, `To`, `Cc`, `Bcc`, `Subject`, `Date`, `Message-ID`, `DKIM-Signature`, `Return-Path`, `Reply-To`, …) is a 400 `MAIL_HEADER_NOT_ALLOWED`: use the matching field (`reply_to` for `Reply-To`).","additionalProperties":{"type":"string"},"example":{"x-entity-ref-id":"order-1234"}},"tags":{"description":"Up to 10 `{ name, value }` labels, stored on every message of the send. Filter sends by them with `GET /emails?tag[name]=value`.","maxItems":10,"example":[{"name":"category","value":"confirm_email"}],"type":"array","items":{"$ref":"#/components/schemas/EmailTagDto"}}},"required":["from","to"]},"SendEmailResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"The email's id. Pass it to `GET /emails/{id}`; it is also the id of the first recipient's message (`GET /messages/{id}`), and webhook events of every recipient carry their own message id as `email_id`.","format":"uuid","example":"4f8b2c1e-9a3d-4e57-b6f0-2d1c8e7a9b05"}},"required":["id"],"x-pc-sdk-model":"SendEmail"},"SendEmailBatchRowDto":{"type":"object","properties":{"from":{"type":"string","description":"Sender. Either a bare address (`hello@acme.com`) or a display name plus the address in angle brackets (`Acme <hello@acme.com>`; quote a name that contains a comma: `\"Acme, Inc.\" <hello@acme.com>`). The display name is at most 200 characters. The address's domain must itself be an active (verified) sending domain of the workspace; a verified subdomain does not cover its parent (with only `mail.acme.com` verified, `hello@acme.com` is refused with 422 `from_domain_not_verified`).","example":"Acme <hello@mail.acme.com>"},"to":{"description":"Recipient: one address, or an array. At most 50 distinct recipients across `to`, `cc` and `bcc` (400 `RECIPIENT_LIMIT`). Each recipient gets its own copy, with its own suppression check, message (`GET /messages`) and delivery status, showing the full `To` and `Cc` lists.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["success@simulator.amazonses.com"]},"cc":{"description":"Cc recipients: one address or an array. Shown in the `Cc` header to every recipient.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["finance@example.com"]},"bcc":{"description":"Bcc recipients: one address or an array. Each gets the message; no header names them.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":["audit@example.com"]},"reply_to":{"description":"Reply-To address(es): one address or an array. This is the only way to set `Reply-To`.","oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}],"example":"support@acme.com"},"subject":{"type":"string","description":"Subject line. Required with `html`/`text`; with a `template` it overrides the template's subject.","maxLength":998,"example":"Your order has shipped"},"html":{"type":"string","description":"HTML body, sent exactly as given (no templating). With no `text`, the plain-text part is derived from it.","maxLength":512000,"example":"<p>Your order has shipped.</p>"},"text":{"type":"string","description":"Plain-text body, sent exactly as given.","maxLength":512000,"example":"Your order has shipped."},"template":{"description":"Send a saved template instead of `html`/`text` (400 `EMAIL_CONTENT_CONFLICT` with both, or with neither).","allOf":[{"$ref":"#/components/schemas/EmailTemplateRefDto"}]},"headers":{"type":"object","description":"Custom headers, as a map of header name to value, kept exactly as sent. Allowed: `X-*` (except `X-SES-*`), `List-Unsubscribe`, `List-Unsubscribe-Post`, `List-Id`, `In-Reply-To` and `References`; at most 50, values up to 998 characters with no line breaks. Any other header (`From`, `To`, `Cc`, `Bcc`, `Subject`, `Date`, `Message-ID`, `DKIM-Signature`, `Return-Path`, `Reply-To`, …) is a 400 `MAIL_HEADER_NOT_ALLOWED`: use the matching field (`reply_to` for `Reply-To`).","additionalProperties":{"type":"string"},"example":{"x-entity-ref-id":"order-1234"}},"tags":{"description":"Up to 10 `{ name, value }` labels, stored on every message of the send. Filter sends by them with `GET /emails?tag[name]=value`.","maxItems":10,"example":[{"name":"category","value":"confirm_email"}],"type":"array","items":{"$ref":"#/components/schemas/EmailTagDto"}},"idempotency_key":{"type":"string","description":"Per-row idempotency key. Same dedupe namespace as the `Idempotency-Key` request header (which must differ from every row key).","maxLength":256,"example":"order-1234-shipped"}},"required":["from","to"]},"SendEmailBatchDto":{"type":"object","properties":{"emails":{"description":"Up to 100 emails, each processed independently: partial success is allowed and every row reports its own `accepted` / `rejected` status.","minItems":1,"maxItems":100,"type":"array","items":{"$ref":"#/components/schemas/SendEmailBatchRowDto"}}},"required":["emails"]},"EmailDto":{"type":"object","properties":{"id":{"type":"string","description":"The email id.","format":"uuid"},"from":{"type":"string","description":"The From address (bare address).","format":"email"},"to":{"description":"The `To` recipients.","type":"array","items":{"type":"string"}},"cc":{"description":"Cc recipients.","type":"array","items":{"type":"string"}},"bcc":{"description":"Bcc recipients.","type":"array","items":{"type":"string"}},"reply_to":{"description":"Reply-To addresses.","type":"array","items":{"type":"string"}},"subject":{"type":"string","description":"Subject line; null when the email has none.","nullable":true},"template_name":{"type":"string","nullable":true,"description":"The template it was rendered from; null for html/text sends."},"tags":{"description":"Tags attached to the email.","type":"array","items":{"$ref":"#/components/schemas/EmailTagDto"}},"last_event":{"description":"The worst status across the email's messages, worst first: complained, bounced, failed, suppressed, deferred, queued, sent, delivered. One message still queued keeps an otherwise delivered email `queued`.","allOf":[{"$ref":"#/components/schemas/MessageStatus"}]},"recipient_count":{"type":"number","description":"Recipients, one message each."},"created_at":{"type":"string","description":"When the email was accepted.","format":"date-time"}},"required":["id","from","to","cc","bcc","reply_to","subject","template_name","tags","last_event","recipient_count","created_at"],"x-pc-sdk-model":"Email"},"EmailPaginationDto":{"type":"object","properties":{"has_more":{"type":"boolean","description":"Whether more emails follow this page."},"next_cursor":{"type":"string","description":"Cursor for the next page; null on the last page.","nullable":true}},"required":["has_more","next_cursor"],"x-pc-sdk-model":"EmailPagination"},"ListEmailsResponseDto":{"type":"object","properties":{"data":{"description":"The emails on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/EmailDto"}},"pagination":{"$ref":"#/components/schemas/EmailPaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListEmails"},"EmailMessageSummaryDto":{"type":"object","properties":{"id":{"type":"string","description":"The message id (`GET /messages/{id}`).","format":"uuid"},"to":{"type":"string","description":"The recipient.","format":"email"},"status":{"description":"This recipient's delivery status.","allOf":[{"$ref":"#/components/schemas/MessageStatus"}]}},"required":["id","to","status"],"x-pc-sdk-model":"EmailMessageSummary"},"EmailDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"The email id.","format":"uuid"},"from":{"type":"string","description":"The From address (bare address).","format":"email"},"to":{"description":"The `To` recipients.","type":"array","items":{"type":"string"}},"cc":{"description":"Cc recipients.","type":"array","items":{"type":"string"}},"bcc":{"description":"Bcc recipients.","type":"array","items":{"type":"string"}},"reply_to":{"description":"Reply-To addresses.","type":"array","items":{"type":"string"}},"subject":{"type":"string","description":"Subject line; null when the email has none.","nullable":true},"template_name":{"type":"string","nullable":true,"description":"The template it was rendered from; null for html/text sends."},"tags":{"description":"Tags attached to the email.","type":"array","items":{"$ref":"#/components/schemas/EmailTagDto"}},"last_event":{"description":"The worst status across the email's messages, worst first: complained, bounced, failed, suppressed, deferred, queued, sent, delivered. One message still queued keeps an otherwise delivered email `queued`.","allOf":[{"$ref":"#/components/schemas/MessageStatus"}]},"recipient_count":{"type":"number","description":"Recipients, one message each."},"created_at":{"type":"string","description":"When the email was accepted.","format":"date-time"},"headers":{"type":"object","description":"The custom headers as sent. Values of headers whose names suggest a credential (auth, token, secret, key, signature, cookie, session) read `[redacted]`.","additionalProperties":{"type":"string"}},"messages":{"description":"One message per recipient, in send order.","type":"array","items":{"$ref":"#/components/schemas/EmailMessageSummaryDto"}}},"required":["id","from","to","cc","bcc","reply_to","subject","template_name","tags","last_event","recipient_count","created_at","headers","messages"],"x-pc-sdk-model":"EmailDetail"},"CreateBroadcastDto":{"type":"object","properties":{"name":{"type":"string","description":"Internal name of the broadcast (not shown to recipients).","minLength":1,"maxLength":100,"example":"October product update"},"from":{"type":"string","description":"Sender: `ada@example.com` or `Ada <ada@example.com>`, on an active sending domain of this workspace. Omit to use the workspace default sender (resolved and fixed when the broadcast is sent).","maxLength":320,"nullable":true,"example":"Acme <news@acme.com>"},"subject":{"type":"string","description":"Subject (Handlebars). Required with `html`; with `template_name`, overrides the template subject.","maxLength":998,"nullable":true},"template_name":{"type":"string","description":"A saved template of this workspace, instead of `html`.","nullable":true,"example":"october-update"},"html":{"type":"string","description":"Inline HTML body (Handlebars), instead of `template_name`. Rendered per recipient with the contact as data (`{{first_name}}`, `{{email}}`, property keys, or `{{contact.plan}}`). Must contain `{{{unsubscribe_url}}}` before the broadcast can be sent.","maxLength":100000,"nullable":true},"text":{"type":"string","description":"Optional plain-text part (Handlebars). Derived from the HTML when omitted. When given, it must contain `{{{unsubscribe_url}}}` too.","maxLength":100000,"nullable":true},"segment_id":{"type":"string","format":"uuid","nullable":true,"description":"Target segment. With `topic_id` too, the audience is both."},"topic_id":{"type":"string","format":"uuid","nullable":true,"description":"Target topic: only contacts subscribed to it (opted in, or default `opt_in` with recorded consent)."},"scheduled_at":{"type":"string","format":"date-time","nullable":true,"description":"Default send time used by `POST .../send` when it gives none."},"rate_per_minute":{"type":"number","description":"Messages per minute for this broadcast, 1 to 300. Omit to use the workspace setting (`GET /broadcast-settings`, default 120). Campaign mail has its own limit, separate from the transactional send limit.","minimum":1,"maximum":300,"nullable":true}},"required":["name"]},"BroadcastStatus":{"type":"string","enum":["draft","scheduled","sending","sent","canceled"]},"BroadcastCountsDto":{"type":"object","properties":{"recipients":{"type":"number","description":"Recipients the audience froze to when the send started.","example":5},"pending":{"type":"number","description":"Not handed to the mail provider yet.","example":0},"sent":{"type":"number","description":"Handed to the mail provider.","example":5},"skipped":{"type":"number","description":"Left out at send time: suppressed, or unsubscribed after the audience froze.","example":0},"failed":{"type":"number","description":"Could not be sent (`error_code` on the recipient).","example":0},"canceled":{"type":"number","description":"Not sent because the broadcast was canceled.","example":0},"delivered":{"type":"number","description":"Accepted by the recipient server (a provider `Delivery` event).","example":4},"bounced":{"type":"number","description":"Bounced.","example":1},"complained":{"type":"number","description":"Marked as spam by the recipient.","example":0},"opened":{"type":"number","description":"Opened at least once. Counted once open tracking is enabled for the workspace; 0 until then.","example":0},"clicked":{"type":"number","description":"Clicked a link at least once. Counted once click tracking is enabled; 0 until then.","example":0},"unsubscribed":{"type":"number","description":"Recipients who unsubscribed (globally, or from the broadcast topic) since the send started.","example":0}},"required":["recipients","pending","sent","skipped","failed","canceled","delivered","bounced","complained","opened","clicked","unsubscribed"],"x-pc-sdk-model":"BroadcastCounts"},"BroadcastDto":{"type":"object","properties":{"id":{"type":"string","description":"The broadcast id.","format":"uuid"},"name":{"type":"string","description":"Internal name of the broadcast (not shown to recipients).","example":"October product update"},"from":{"type":"string","nullable":true,"example":"Acme <news@acme.com>","description":"Null on a draft that uses the workspace default sender."},"subject":{"type":"string","description":"Subject line; null until set (or when the template supplies it).","nullable":true,"example":"What shipped in October"},"template_name":{"type":"string","description":"Template the broadcast renders; null when it has its own content.","nullable":true,"example":"october-update"},"html":{"type":"string","nullable":true,"description":"Inline HTML body; null when a template is used."},"text":{"type":"string","description":"Plain-text body; null when only HTML or a template is used.","nullable":true},"segment_id":{"type":"string","format":"uuid","nullable":true,"description":"Null when only a topic targets it, or the segment was deleted."},"topic_id":{"type":"string","description":"Topic the broadcast is sent on; recipients who opted out of it are skipped. Null for none.","format":"uuid","nullable":true},"status":{"description":"`draft`: editable. `scheduled`: waiting for `scheduled_at`. `sending`: going out. `sent`: every recipient handled. `canceled`: stopped before the end.","allOf":[{"$ref":"#/components/schemas/BroadcastStatus"}]},"scheduled_at":{"type":"string","description":"When the broadcast is scheduled to go out; null when not scheduled.","format":"date-time","nullable":true},"started_at":{"type":"string","format":"date-time","nullable":true,"description":"When the audience froze and sending began."},"completed_at":{"type":"string","description":"When sending finished; null until then.","format":"date-time","nullable":true},"canceled_at":{"type":"string","description":"When the broadcast was canceled; null when it was not.","format":"date-time","nullable":true},"rate_per_minute":{"type":"number","nullable":true,"minimum":1,"maximum":300,"description":"Null: the workspace setting."},"failure_reason":{"type":"string","nullable":true,"description":"Why the broadcast stopped on its own (its segment or topic was deleted)."},"counts":{"nullable":true,"description":"Null on a draft or a broadcast still scheduled.","allOf":[{"$ref":"#/components/schemas/BroadcastCountsDto"}]},"created_at":{"type":"string","description":"When the broadcast was created.","format":"date-time"},"updated_at":{"type":"string","description":"When the broadcast was last changed.","format":"date-time"}},"required":["id","name","from","subject","template_name","html","text","segment_id","topic_id","status","scheduled_at","started_at","completed_at","canceled_at","rate_per_minute","failure_reason","counts","created_at","updated_at"],"x-pc-sdk-model":"Broadcast"},"ListBroadcastsResponseDto":{"type":"object","properties":{"data":{"description":"The broadcasts on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/BroadcastDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListBroadcasts"},"BroadcastAudienceDto":{"type":"object","properties":{"recipients":{"type":"number","description":"Who a send started now would reach: segment ∩ topic subscribers − unsubscribed − suppressed.","example":1180},"segment_contacts":{"type":"number","nullable":true,"description":"Everyone in the segment, before the exclusions. Null without a segment.","example":1240},"computed_at":{"type":"string","description":"When the counts were computed.","format":"date-time"}},"required":["recipients","segment_contacts","computed_at"],"x-pc-sdk-model":"BroadcastAudience"},"UpdateBroadcastDto":{"type":"object","properties":{"name":{"type":"string","description":"New internal name.","minLength":1,"maxLength":100},"from":{"type":"string","description":"Sender: `ada@example.com` or `Ada <ada@example.com>`, on an active sending domain of this workspace. Omit to use the workspace default sender (resolved and fixed when the broadcast is sent).","maxLength":320,"nullable":true},"subject":{"type":"string","description":"New subject line; null clears it.","maxLength":998,"nullable":true},"template_name":{"type":"string","nullable":true,"description":"Set to null to switch to inline `html`."},"html":{"type":"string","description":"Inline HTML body (Handlebars), instead of `template_name`. Rendered per recipient with the contact as data (`{{first_name}}`, `{{email}}`, property keys, or `{{contact.plan}}`). Must contain `{{{unsubscribe_url}}}` before the broadcast can be sent.","maxLength":100000,"nullable":true},"text":{"type":"string","description":"Optional plain-text part (Handlebars). Derived from the HTML when omitted. When given, it must contain `{{{unsubscribe_url}}}` too.","maxLength":100000,"nullable":true},"segment_id":{"type":"string","description":"Segment to send to; null sends to every subscribed contact.","format":"uuid","nullable":true},"topic_id":{"type":"string","description":"Topic to send on; null for none.","format":"uuid","nullable":true},"scheduled_at":{"type":"string","description":"When to send; null clears the schedule.","format":"date-time","nullable":true},"rate_per_minute":{"type":"number","description":"Messages per minute for this broadcast, 1 to 300. Omit to use the workspace setting (`GET /broadcast-settings`, default 120). Campaign mail has its own limit, separate from the transactional send limit.","minimum":1,"maximum":300,"nullable":true}}},"SendBroadcastDto":{"type":"object","properties":{"scheduled_at":{"type":"string","format":"date-time","nullable":true,"description":"Send at this time instead of now (the draft `scheduled_at` when omitted; null forces now). The audience is frozen when sending starts, so people who unsubscribe meanwhile are left out.","example":"2026-11-02T09:00:00Z"}}},"BroadcastRecipientStatus":{"type":"string","enum":["pending","sending","sent","skipped","failed","canceled"]},"BroadcastRecipientDto":{"type":"object","properties":{"id":{"type":"string","description":"The recipient row id.","format":"uuid"},"email":{"type":"string","description":"The recipient's email address.","format":"email","example":"ada@example.com"},"contact_id":{"type":"string","format":"uuid","nullable":true,"description":"Null when the contact was deleted since."},"status":{"description":"`pending`: waiting. `sending`: being handed off. `sent`: handed to the provider (see `message_status`). `skipped`: left out at send time. `failed`: see `error_code`. `canceled`: the broadcast was canceled first.","allOf":[{"$ref":"#/components/schemas/BroadcastRecipientStatus"}]},"message_id":{"type":"string","format":"uuid","nullable":true,"description":"The message (`GET /messages/{id}`), once sent."},"message_status":{"type":"string","nullable":true,"example":"delivered","description":"The message status: `queued`, `sent`, `delivered`, `bounced`, `complained`, `deferred`, `failed`."},"error_code":{"type":"string","description":"Machine-readable reason the recipient was not sent to; null when sent.","nullable":true,"example":"RECIPIENT_SUPPRESSED"},"error":{"type":"string","description":"Human-readable reason the recipient was not sent to; null when sent.","nullable":true},"sent_at":{"type":"string","description":"When the email to this recipient was sent; null until then.","format":"date-time","nullable":true}},"required":["id","email","contact_id","status","message_id","message_status","error_code","error","sent_at"],"x-pc-sdk-model":"BroadcastRecipient"},"ListBroadcastRecipientsResponseDto":{"type":"object","properties":{"data":{"description":"The recipients on this page.","type":"array","items":{"$ref":"#/components/schemas/BroadcastRecipientDto"}},"pagination":{"$ref":"#/components/schemas/PaginationDto"}},"required":["data","pagination"],"x-pc-sdk-model":"ListBroadcastRecipients"},"ClickedLinkDto":{"type":"object","properties":{"url":{"type":"string","description":"The link that was clicked.","format":"uri","example":"https://acme.com/blog/october"},"clicks":{"type":"number","description":"How many clicks the link got.","example":12},"unique_recipients":{"type":"number","example":9,"description":"Distinct recipients who clicked it."}},"required":["url","clicks","unique_recipients"],"x-pc-sdk-model":"ClickedLink"},"ClickedLinksResponseDto":{"type":"object","properties":{"data":{"description":"Most clicked first, at most 100. Empty until click tracking is enabled for the workspace.","type":"array","items":{"$ref":"#/components/schemas/ClickedLinkDto"}}},"required":["data"],"x-pc-sdk-model":"ClickedLinks"},"BroadcastSettingsDto":{"type":"object","properties":{"rate_per_minute":{"type":"number","nullable":true,"minimum":1,"maximum":300,"description":"The workspace campaign pace; null uses the default."},"effective_rate_per_minute":{"type":"number","example":120,"description":"What a broadcast without its own rate is sent at."},"default_rate_per_minute":{"type":"number","description":"Default sending rate for new broadcasts, in emails per minute.","example":120}},"required":["rate_per_minute","effective_rate_per_minute","default_rate_per_minute"],"x-pc-sdk-model":"BroadcastSettings"},"UpdateBroadcastSettingsDto":{"type":"object","properties":{"rate_per_minute":{"type":"number","nullable":true,"minimum":1,"maximum":300,"description":"Null restores the default (120 per minute)."}},"required":["rate_per_minute"]},"IntegrationStatus":{"type":"string","enum":["active","error","revoked"]},"IntegrationListItemDto":{"type":"object","properties":{"provider":{"type":"string","description":"Integration provider id.","example":"github"},"display_name":{"type":"string","description":"Display name of the provider.","example":"GitHub"},"account_login":{"type":"string","description":"Account login at the provider that was connected.","example":"octocat"},"account_avatar_url":{"type":"string","description":"Avatar of the connected account; null when the provider has none.","format":"uri","example":"https://avatars.githubusercontent.com/u/1?v=4","nullable":true},"status":{"description":"Connection health: `active`, `error` (the last call failed) or `revoked` (access was withdrawn at the provider).","example":"active","allOf":[{"$ref":"#/components/schemas/IntegrationStatus"}]},"last_error":{"type":"string","description":"Surfaced when status is 'error' — last failure message.","nullable":true},"last_synced_at":{"format":"date-time","type":"string","description":"When the last successful sync ran. null until first success.","nullable":true},"settings":{"type":"object","description":"Provider-specific non-secret settings (e.g. selected repo / branch / path).","additionalProperties":true},"updated_at":{"format":"date-time","type":"string","description":"When the connection was last changed."}},"required":["provider","display_name","account_login","account_avatar_url","status","last_error","last_synced_at","settings","updated_at"],"x-pc-sdk-model":"IntegrationListItem"},"ListIntegrationsResponseDto":{"type":"object","properties":{"data":{"description":"The connected integrations.","type":"array","items":{"$ref":"#/components/schemas/IntegrationListItemDto"}}},"required":["data"],"x-pc-sdk-model":"ListIntegrations"},"IntegrationDetailDto":{"type":"object","properties":{"provider":{"type":"string","description":"Integration provider id.","example":"github"},"display_name":{"type":"string","description":"Display name of the provider.","example":"GitHub"},"account_login":{"type":"string","description":"Account login at the provider that was connected.","example":"octocat"},"account_avatar_url":{"type":"string","description":"Avatar of the connected account; null when the provider has none.","format":"uri","example":"https://avatars.githubusercontent.com/u/1?v=4","nullable":true},"status":{"description":"Connection health: `active`, `error` (the last call failed) or `revoked` (access was withdrawn at the provider).","example":"active","allOf":[{"$ref":"#/components/schemas/IntegrationStatus"}]},"last_error":{"type":"string","description":"Surfaced when status is 'error' — last failure message.","nullable":true},"last_synced_at":{"format":"date-time","type":"string","description":"When the last successful sync ran. null until first success.","nullable":true},"settings":{"type":"object","description":"Provider-specific non-secret settings (e.g. selected repo / branch / path).","additionalProperties":true},"updated_at":{"format":"date-time","type":"string","description":"When the connection was last changed."},"credentials_redacted":{"type":"object","description":"Provider's redacted credential view — public identifiers + a 'token_present' boolean. Secrets NEVER round-trip.","additionalProperties":true}},"required":["provider","display_name","account_login","account_avatar_url","status","last_error","last_synced_at","settings","updated_at","credentials_redacted"],"x-pc-sdk-model":"IntegrationDetail"},"GitHubRepoDto":{"type":"object","properties":{"full_name":{"type":"string","description":"The repository as `<owner>/<repo>`."},"default_branch":{"type":"string","description":"The repository's default branch."},"private":{"type":"boolean","description":"True for a private repository."},"html_url":{"type":"string","description":"The repository on github.com.","format":"uri"},"updated_at":{"type":"string","description":"When the repository was last pushed to or changed.","format":"date-time"}},"required":["full_name","default_branch","private","html_url","updated_at"],"x-pc-sdk-model":"GitHubRepo"},"GitHubBranchDto":{"type":"object","properties":{"name":{"type":"string","description":"The branch name."}},"required":["name"],"x-pc-sdk-model":"GitHubBranch"},"UpdateGitHubSettingsDto":{"type":"object","properties":{"repo_full_name":{"type":"string","description":"Repository to sync templates from, as `<owner>/<repo>`.","example":"octocat/templates"},"branch":{"type":"string","description":"Branch to sync from.","example":"main"},"templates_path":{"type":"string","description":"Directory in the repository that holds the templates (`/` for the root).","example":"/"}},"required":["repo_full_name","branch","templates_path"]},"StartSyncResponseDto":{"type":"object","properties":{"sync_id":{"type":"string","description":"Opaque sync-run id (base64url)."},"started_at":{"type":"string","description":"When the sync started.","format":"date-time"}},"required":["sync_id","started_at"],"x-pc-sdk-model":"StartSync"},"IntegrationSyncState":{"type":"string","enum":["running","completed","failed"]},"SyncStatusDto":{"type":"object","properties":{"status":{"description":"Where the sync is: `running`, then `completed` or `failed`.","allOf":[{"$ref":"#/components/schemas/IntegrationSyncState"}]},"started_at":{"type":"string","description":"When the sync started.","format":"date-time"},"ended_at":{"type":"string","description":"When the sync finished; null while running.","format":"date-time","nullable":true},"summary":{"type":"object","description":"Counts of what the sync changed; null while running.","additionalProperties":true,"nullable":true},"error":{"type":"string","description":"Why the sync failed; null unless `failed`.","nullable":true}},"required":["status","started_at","ended_at","summary","error"],"x-pc-sdk-model":"SyncStatus"},"ConnectGitHubRequestDto":{"type":"object","properties":{"return_to":{"type":"string","description":"URL the workspace user should land on after the GitHub OAuth flow completes. Must be a same-origin or productcraft.co URL — anything else is rejected to keep the callback from being an open-redirect.","example":"https://console.productcraft.co/mail/workspaces/acme/integrations","maxLength":2048}},"required":["return_to"]},"ConnectGitHubResponseDto":{"type":"object","properties":{"authorize_url":{"type":"string","description":"Browser redirects here to start the GitHub OAuth flow.","format":"uri","example":"https://github.com/login/oauth/authorize?client_id=…&state=…&redirect_uri=…"}},"required":["authorize_url"],"x-pc-sdk-model":"ConnectGitHub"},"EmailSentEvent":{"type":"object","title":"EmailSentEvent","description":"The message was accepted and we are delivering it to the recipient's mail server. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.sent"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailSentEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.sent","created_at":"2026-11-05T09:00:00.000Z","data":{"email_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","from":"hello@acme.com","to":"success@simulator.amazonses.com","message_id":"<0102019a1b2c3d4e-5f6a@email.amazonses.com>","smtp_response":"250 Ok","sent_at":"2026-10-17T10:00:00.000Z","transport":"ses"}},"x-pc-sdk-model":"EmailSentEvent"},"EmailDeliveredEvent":{"type":"object","title":"EmailDeliveredEvent","description":"The recipient's mail server accepted the message. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.delivered"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailDeliveredEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.delivered","created_at":"2026-11-05T09:00:00.000Z","data":{"email_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","message_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","from":"hello@acme.com","to":"success@simulator.amazonses.com","ses_event":"Delivery","occurred_at":"2026-10-17T10:00:02.000Z"}},"x-pc-sdk-model":"EmailDeliveredEvent"},"EmailDeliveryDelayedEvent":{"type":"object","title":"EmailDeliveryDelayedEvent","description":"Delivery is being retried after a temporary failure. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.delivery_delayed"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailDeliveryDelayedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.delivery_delayed","created_at":"2026-11-05T09:00:00.000Z","data":{"from":"hello@acme.com","to":"success@simulator.amazonses.com","smtp_code":"4.7.0","smtp_response":"421 4.7.0 Try again later","retry_until":"2026-10-18T10:00:00.000Z","deferred_at":"2026-10-17T10:00:02.000Z"}},"x-pc-sdk-model":"EmailDeliveryDelayedEvent"},"EmailBouncedEvent":{"type":"object","title":"EmailBouncedEvent","description":"The message bounced permanently; the address is suppressed. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.bounced"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailBouncedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.bounced","created_at":"2026-11-05T09:00:00.000Z","data":{"from":"hello@acme.com","to":"bounce@simulator.amazonses.com","smtp_code":"5.1.1","smtp_response":"550 5.1.1 user unknown","bounced_at":"2026-10-17T10:00:02.000Z"}},"x-pc-sdk-model":"EmailBouncedEvent"},"EmailComplainedEvent":{"type":"object","title":"EmailComplainedEvent","description":"The recipient marked the message as spam; the address is suppressed. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.complained"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailComplainedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.complained","created_at":"2026-11-05T09:00:00.000Z","data":{"email_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","message_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","from":"hello@acme.com","to":"complaint@simulator.amazonses.com","ses_event":"Complaint","occurred_at":"2026-10-17T10:05:00.000Z"}},"x-pc-sdk-model":"EmailComplainedEvent"},"EmailFailedEvent":{"type":"object","title":"EmailFailedEvent","description":"The message could not be sent because of an error; nothing was sent. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.failed"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailFailedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.failed","created_at":"2026-11-05T09:00:00.000Z","data":{"email_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","message_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","from":"hello@acme.com","to":"success@simulator.amazonses.com","reason":"The template could not be rendered","error":"RenderingFailure","transport":"ses","failed_at":"2026-10-17T10:00:01.000Z"}},"x-pc-sdk-model":"EmailFailedEvent"},"EmailSuppressedEvent":{"type":"object","title":"EmailSuppressedEvent","description":"A send was refused because the recipient is on the suppression list. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.suppressed"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailSuppressedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.suppressed","created_at":"2026-11-05T09:00:00.000Z","data":{"from":"hello@acme.com","to":"suppressionlist@simulator.amazonses.com","template":"welcome","reason":"suppressed","refused_at":"2026-10-17T10:00:00.000Z"}},"x-pc-sdk-model":"EmailSuppressedEvent"},"EmailSkippedEvent":{"type":"object","title":"EmailSkippedEvent","description":"A template send was skipped: it named no sender and the workspace has no default sender set. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.skipped"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailSkippedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.skipped","created_at":"2026-11-05T09:00:00.000Z","data":{"to":"success@simulator.amazonses.com","template":"welcome","reason":"no_default_sender","skipped_at":"2026-10-17T10:00:00.000Z"}},"x-pc-sdk-model":"EmailSkippedEvent"},"EmailScheduledEvent":{"type":"object","title":"EmailScheduledEvent","description":"A message was scheduled for later (scheduled sending; not emitted yet). Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.scheduled"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailScheduledEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.scheduled","created_at":"2026-11-05T09:00:00.000Z","data":{"email_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","from":"hello@acme.com","to":"success@simulator.amazonses.com","scheduled_at":"2026-10-18T09:00:00.000Z"}},"x-pc-sdk-model":"EmailScheduledEvent"},"EmailCanceledEvent":{"type":"object","title":"EmailCanceledEvent","description":"A scheduled message was canceled (scheduled sending; not emitted yet). Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.canceled"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailCanceledEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.canceled","created_at":"2026-11-05T09:00:00.000Z","data":{"email_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","from":"hello@acme.com","to":"success@simulator.amazonses.com","canceled_at":"2026-10-17T12:00:00.000Z"}},"x-pc-sdk-model":"EmailCanceledEvent"},"EmailOpenedEvent":{"type":"object","title":"EmailOpenedEvent","description":"The recipient opened the message (open tracking; not emitted yet). Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.opened"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailOpenedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.opened","created_at":"2026-11-05T09:00:00.000Z","data":{"email_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","to":"success@simulator.amazonses.com","opened_at":"2026-10-17T10:10:00.000Z"}},"x-pc-sdk-model":"EmailOpenedEvent"},"EmailClickedEvent":{"type":"object","title":"EmailClickedEvent","description":"The recipient clicked a link (click tracking; not emitted yet). Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.clicked"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailClickedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.clicked","created_at":"2026-11-05T09:00:00.000Z","data":{"email_id":"0b9d4c1e-5f2a-4e8b-9c3d-7a6b5e4f3d2c","to":"success@simulator.amazonses.com","link":"https://acme.com/welcome","clicked_at":"2026-10-17T10:11:00.000Z"}},"x-pc-sdk-model":"EmailClickedEvent"},"EmailReceivedEvent":{"type":"object","title":"EmailReceivedEvent","description":"A mailbox received a message (inbound webhooks; not emitted yet). Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["email.received"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/EmailReceivedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"email.received","created_at":"2026-11-05T09:00:00.000Z","data":{"from":"customer@example.com","to":"support@acme.com","subject":"Question about my order","received_at":"2026-10-17T10:00:00.000Z"}},"x-pc-sdk-model":"EmailReceivedEvent"},"DomainCreatedEvent":{"type":"object","title":"DomainCreatedEvent","description":"A domain was added to the workspace. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["domain.created"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/DomainCreatedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"domain.created","created_at":"2026-11-05T09:00:00.000Z","data":{"id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","fqdn":"acme.com","status":"pending","health":"ok","intent":"send","created_at":"2026-10-17T09:00:00.000Z"}},"x-pc-sdk-model":"DomainCreatedEvent"},"DomainUpdatedEvent":{"type":"object","title":"DomainUpdatedEvent","description":"A domain's DNS records, signing status or health changed. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["domain.updated"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/DomainUpdatedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"domain.updated","created_at":"2026-11-05T09:00:00.000Z","data":{"id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","fqdn":"acme.com","status":"pending","health":"ok","changes":[{"purpose":"dkim","from":"propagating","to":"verified"}]}},"x-pc-sdk-model":"DomainUpdatedEvent"},"DomainVerifiedEvent":{"type":"object","title":"DomainVerifiedEvent","description":"A domain finished verification and can send. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["domain.verified"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/DomainVerifiedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"domain.verified","created_at":"2026-11-05T09:00:00.000Z","data":{"id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","fqdn":"acme.com","status":"verified","health":"ok","verified_at":"2026-10-17T09:20:00.000Z"}},"x-pc-sdk-model":"DomainVerifiedEvent"},"DomainDeletedEvent":{"type":"object","title":"DomainDeletedEvent","description":"A domain was removed. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["domain.deleted"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/DomainDeletedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"domain.deleted","created_at":"2026-11-05T09:00:00.000Z","data":{"id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","fqdn":"acme.com","status":"verified","health":"ok"}},"x-pc-sdk-model":"DomainDeletedEvent"},"SuppressionAddedEvent":{"type":"object","title":"SuppressionAddedEvent","description":"An address was added to the suppression list (bounce, complaint or by hand). Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["suppression.added"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/SuppressionAddedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"suppression.added","created_at":"2026-11-05T09:00:00.000Z","data":{"email":"bounce@simulator.amazonses.com","reason":"bounce","source":"ses","added_at":"2026-10-17T10:00:03.000Z"}},"x-pc-sdk-model":"SuppressionAddedEvent"},"SuppressionRemovedEvent":{"type":"object","title":"SuppressionRemovedEvent","description":"An address was removed from the suppression list. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["suppression.removed"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/SuppressionRemovedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"suppression.removed","created_at":"2026-11-05T09:00:00.000Z","data":{"email":"bounce@simulator.amazonses.com","removed_at":"2026-10-17T11:00:00.000Z"}},"x-pc-sdk-model":"SuppressionRemovedEvent"},"SendingDefaultsUpdatedEvent":{"type":"object","title":"SendingDefaultsUpdatedEvent","description":"The workspace default sender was set, changed or cleared. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["sending_defaults.updated"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/SendingDefaultsUpdatedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"sending_defaults.updated","created_at":"2026-11-05T09:00:00.000Z","data":{"default_sender":{"address":"Acme <hello@acme.com>","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","domain_status":"verified","verified":true},"previous_address":null,"updated_at":"2026-10-17T09:30:00.000Z"}},"x-pc-sdk-model":"SendingDefaultsUpdatedEvent"},"ContactCreatedEvent":{"type":"object","title":"ContactCreatedEvent","description":"A contact was added (by the API, the dashboard, or an unsubscribe from someone who was not a contact). Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["contact.created"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/ContactEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"contact.created","created_at":"2026-11-05T09:00:00.000Z","data":{"id":"7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f","email":"success@simulator.amazonses.com","first_name":"Ada","last_name":"Lovelace","unsubscribed":false,"created_at":"2026-10-24T10:00:00.000Z","updated_at":"2026-10-24T10:00:00.000Z"}},"x-pc-sdk-model":"ContactCreatedEvent"},"ContactUpdatedEvent":{"type":"object","title":"ContactUpdatedEvent","description":"A contact changed: its fields, its global unsubscribe, or its topic subscriptions (including through an unsubscribe link). Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["contact.updated"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/ContactEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"contact.updated","created_at":"2026-11-05T09:00:00.000Z","data":{"id":"7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f","email":"success@simulator.amazonses.com","first_name":"Ada","last_name":"Lovelace","unsubscribed":true,"created_at":"2026-10-24T10:00:00.000Z","updated_at":"2026-10-24T11:00:00.000Z"}},"x-pc-sdk-model":"ContactUpdatedEvent"},"ContactDeletedEvent":{"type":"object","title":"ContactDeletedEvent","description":"A contact was deleted. Endpoints behind the deprecated per-slot routes also get `X-Mail-Event-Id` and `X-Mail-Event-Type` headers until their sunset.","required":["id","type","created_at","data"],"properties":{"workspace_id":{"type":"string","format":"uuid","description":"The workspace the event belongs to, so you can route without opening `data`. Absent on \"Send test\" deliveries."},"domain_id":{"type":"string","format":"uuid","nullable":true,"description":"The sending domain the event is about; null for workspace-level events (suppression, contacts, settings) and when the domain is unknown. Absent on \"Send test\" deliveries."},"id":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$","example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","description":"The event id, also sent as `webhook-id`; the same on every retry and replay."},"type":{"type":"string","enum":["contact.deleted"],"description":"The event type. Switch on it to narrow the event."},"created_at":{"type":"string","format":"date-time","example":"2026-11-05T09:00:00.000Z","description":"When the event happened (the same on every retry)."},"test":{"type":"boolean","description":"Present and true only on a delivery made by \"Send test\"; its `data` is the catalogue example."},"data":{"$ref":"#/components/schemas/ContactDeletedEventDataDto"}},"example":{"workspace_id":"9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b","domain_id":"5e1f3a2b-8c4d-4e6f-9a0b-1c2d3e4f5a6b","id":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f","type":"contact.deleted","created_at":"2026-11-05T09:00:00.000Z","data":{"id":"7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f","email":"success@simulator.amazonses.com","first_name":"Ada","last_name":"Lovelace","unsubscribed":true,"created_at":"2026-10-24T10:00:00.000Z","updated_at":"2026-10-24T11:00:00.000Z","deleted_at":"2026-10-24T12:00:00.000Z"}},"x-pc-sdk-model":"ContactDeletedEvent"},"MailErrorCode":{"description":"Error codes this API returns (open set: a client must accept codes it does not know; new codes are not a breaking change). Each is documented at https://productcraft.co/docs/errors#<code>.","anyOf":[{"type":"string","enum":["BAD_REQUEST","VALIDATION_ERROR","UNAUTHORIZED","PAYMENT_REQUIRED","FORBIDDEN","NOT_FOUND","METHOD_NOT_ALLOWED","NOT_ACCEPTABLE","REQUEST_TIMEOUT","CONFLICT","GONE","PRECONDITION_FAILED","PAYLOAD_TOO_LARGE","UNSUPPORTED_MEDIA_TYPE","UNPROCESSABLE_ENTITY","PRECONDITION_REQUIRED","RATE_LIMITED","INTERNAL_SERVER_ERROR","NOT_IMPLEMENTED","BAD_GATEWAY","SERVICE_UNAVAILABLE","GATEWAY_TIMEOUT","SERVICE_NOT_ENABLED","INVALID_CREDENTIALS","SESSION_REVOKED","MCP_NOT_PERMITTED","MCP_WORKSPACE_MISMATCH","PAK_NOT_PERMITTED","ACTIONS_NOT_GRANTABLE","IDEMPOTENCY_KEY_REUSE","IDEMPOTENCY_KEY_REQUIRED","IDEMPOTENCY_IN_PROGRESS","WEBHOOK_ENDPOINT_LIMIT","WEBHOOK_ENDPOINT_NOT_FOUND","WEBHOOK_ENDPOINT_NOT_SUBSCRIBED","WEBHOOK_EVENT_NOT_FOUND","WEBHOOK_EVENT_TYPE_UNKNOWN","AUDIENCE_REQUIRED","BROADCAST_AUDIENCE_EMPTY","BROADCAST_CONTENT_CONFLICT","BROADCAST_NOT_CANCELABLE","BROADCAST_NOT_DELETABLE","BROADCAST_NOT_DRAFT","BROADCAST_NOT_FOUND","BROADCAST_NOT_READY","CAPABILITY_NOT_VERIFIED","CONTACT_EXISTS","CONTACT_LIMIT","CONTACT_NOT_FOUND","CONTACT_PROPERTY_EXISTS","CONTACT_PROPERTY_LIMIT","CONTACT_PROPERTY_NOT_FOUND","DATE_RANGE_BEYOND_RETENTION","DATE_RANGE_TOO_WIDE","DATE_WINDOW_TOO_WIDE","DKIM_KEY_MISSING","DNS_CONFLICTS","DOMAIN_CONNECT_DISABLED","DOMAIN_CONNECT_MAIL_FROM_LABEL","DOMAIN_CONNECT_NOT_SENDING","DOMAIN_CONNECT_UNAVAILABLE","DOMAIN_HAS_MAILBOXES","DOMAIN_NOT_FOUND","EMAIL_CONTENT_CONFLICT","EMAIL_NOT_FOUND","EMAIL_UNAVAILABLE","FROM_DOMAIN_MISMATCH","IDEMPOTENCY_KEY_CONFLICTS_WITH_ROW","IMPORT_IN_PROGRESS","IMPORT_NOT_FOUND","IMPORT_TOO_LARGE","INVALID_CAPABILITIES","INVALID_CONTACT_PROPERTY_VALUE","INVALID_CSV","INVALID_DATE","INVALID_DATE_RANGE","INVALID_DATE_WINDOW","INVALID_FORMAT","INVALID_FROM_ADDRESS","INVALID_SEGMENT_RULE","INVALID_TIMEZONE","INVALID_ZONE","MAIL_FROM_HOST_IN_USE","MAIL_FROM_NOT_SENDING","MAIL_HEADER_NOT_ALLOWED","PROVIDER_ERROR","PROVIDER_PERMISSION_DENIED","PROVIDER_TOKEN_REJECTED","PROVIDER_UNAVAILABLE","PROVIDER_ZONE_NOT_FOUND","RECIPIENT_LIMIT","RECIPIENT_SUPPRESSED","REGION_NOT_AVAILABLE","RESERVED_PROPERTY_KEY","SEGMENT_EXISTS","SEGMENT_LIMIT","SEGMENT_NOT_FOUND","SEGMENT_RULE_BASED","SEGMENT_TYPE_FIXED","SES_IDENTITY_DELETE_FAILED","SHARE_LINK_NOT_FOUND","SMTP_AUTH_PARTIAL","SMTP_CONFIG_NOT_FOUND","SMTP_PASSWORD_REQUIRED","TEMPLATE_DATA_INVALID","TEMPLATE_KIND_NOT_SENDABLE","TEMPLATE_NOT_FOUND","TEMPLATE_RENDER_FAILED","TLS_ENFORCED_NOT_AVAILABLE","TOPIC_EXISTS","TOPIC_LIMIT","TOPIC_NOT_FOUND","TRACKING_NOT_AVAILABLE","UNKNOWN_CONTACT_PROPERTY","UNSUBSCRIBE_LINK_REQUIRED","domain_not_verified_by_provider","from_domain_not_verified","no_default_sender","sender_domain_not_in_workspace"]},{"type":"string","description":"A code added after this document was published."}],"x-pc-open-enum":true,"x-pc-error-docs":"https://productcraft.co/docs/errors#{code}","x-enum-descriptions":{"BAD_REQUEST":"The request is malformed (not valid JSON, a bad header, an unusable parameter).","VALIDATION_ERROR":"One or more request fields are invalid; `errors` lists each field (`param`, `message`, `code`).","UNAUTHORIZED":"No credentials, or the token or API key is invalid, expired or revoked.","PAYMENT_REQUIRED":"The workspace has no credit or plan for this operation.","FORBIDDEN":"The caller is authenticated but not allowed to do this.","NOT_FOUND":"The resource does not exist, or belongs to another workspace or app.","METHOD_NOT_ALLOWED":"The route does not accept this HTTP method.","NOT_ACCEPTABLE":"The route cannot produce the requested content type.","REQUEST_TIMEOUT":"The request took too long to arrive.","CONFLICT":"The request conflicts with the current state of the resource.","GONE":"The resource existed but has been removed for good.","PRECONDITION_FAILED":"A precondition header did not match.","PAYLOAD_TOO_LARGE":"The request body is over the size limit.","UNSUPPORTED_MEDIA_TYPE":"The request body is not in a content type the route accepts.","UNPROCESSABLE_ENTITY":"The request is well-formed but cannot be carried out.","PRECONDITION_REQUIRED":"The route requires a precondition header.","RATE_LIMITED":"Too many requests; retry after the `Retry-After` header.","INTERNAL_SERVER_ERROR":"An unexpected server error. Retrying is safe for idempotent requests; quote `request_id` to support.","NOT_IMPLEMENTED":"The server does not support this operation.","BAD_GATEWAY":"An upstream service returned an invalid response.","SERVICE_UNAVAILABLE":"The service or one of its dependencies is temporarily unavailable; retry.","GATEWAY_TIMEOUT":"An upstream service did not answer in time; retry.","SERVICE_NOT_ENABLED":"The workspace has not enabled this product.","INVALID_CREDENTIALS":"The credentials were not accepted.","SESSION_REVOKED":"The session behind this token was signed out or revoked.","MCP_NOT_PERMITTED":"An MCP (agent) token cannot call this route.","MCP_WORKSPACE_MISMATCH":"The MCP token was issued for a different workspace.","PAK_NOT_PERMITTED":"A workspace API key cannot call this route.","ACTIONS_NOT_GRANTABLE":"The policy grants actions the caller does not hold.","IDEMPOTENCY_KEY_REUSE":"The `Idempotency-Key` was already used with a different body or route.","IDEMPOTENCY_KEY_REQUIRED":"This operation requires an `Idempotency-Key` header.","IDEMPOTENCY_IN_PROGRESS":"A request with the same `Idempotency-Key` is still running. Retry after `Retry-After` seconds with the same key to get its response.","WEBHOOK_ENDPOINT_LIMIT":"The workspace has the maximum number of webhook endpoints.","WEBHOOK_ENDPOINT_NOT_FOUND":"No webhook endpoint with this id in this workspace.","WEBHOOK_ENDPOINT_NOT_SUBSCRIBED":"The endpoint is not subscribed to this event type.","WEBHOOK_EVENT_NOT_FOUND":"No webhook event with this id in this workspace.","WEBHOOK_EVENT_TYPE_UNKNOWN":"The event type is not one this product sends.","AUDIENCE_REQUIRED":"Pass segment_id, topic_id, or both.","BROADCAST_AUDIENCE_EMPTY":"Nobody in this audience can receive the broadcast.","BROADCAST_CONTENT_CONFLICT":"Use a template or inline html, not both.","BROADCAST_NOT_CANCELABLE":"The broadcast cannot be canceled in its current status.","BROADCAST_NOT_DELETABLE":"The broadcast cannot be deleted in its current status; cancel it first.","BROADCAST_NOT_DRAFT":"The broadcast is no longer a draft (`details.status`).","BROADCAST_NOT_FOUND":"Broadcast not found.","BROADCAST_NOT_READY":"The broadcast cannot be sent yet (`details.problems`).","CAPABILITY_NOT_VERIFIED":"A verified domain cannot gain sending or receiving until the new records verify (`details.records`).","CONTACT_EXISTS":"A contact with this email already exists.","CONTACT_LIMIT":"The workspace has the maximum number of contacts.","CONTACT_NOT_FOUND":"Contact not found.","CONTACT_PROPERTY_EXISTS":"A contact property with this key already exists.","CONTACT_PROPERTY_LIMIT":"The workspace has the maximum number of contact properties.","CONTACT_PROPERTY_NOT_FOUND":"Contact property not found.","DATE_RANGE_BEYOND_RETENTION":"The date range reaches past the data retention window.","DATE_RANGE_TOO_WIDE":"The date range is wider than allowed.","DATE_WINDOW_TOO_WIDE":"The date window is longer than the message log retention.","DKIM_KEY_MISSING":"The domain has no DKIM key yet.","DNS_CONFLICTS":"Some records cannot be written without breaking existing ones; nothing was changed.","DOMAIN_CONNECT_DISABLED":"Domain Connect is turned off.","DOMAIN_CONNECT_MAIL_FROM_LABEL":"Domain Connect cannot apply a custom MAIL FROM label.","DOMAIN_CONNECT_NOT_SENDING":"Domain Connect needs a sending domain.","DOMAIN_CONNECT_UNAVAILABLE":"The DNS provider does not support Domain Connect for this domain.","DOMAIN_HAS_MAILBOXES":"The domain still has active mailboxes (`details.mailboxes`).","DOMAIN_NOT_FOUND":"Domain not found in this workspace.","EMAIL_CONTENT_CONFLICT":"Send either `html`/`text` or a `template`, not both, and at least one of them.","EMAIL_NOT_FOUND":"Email not found in this workspace.","EMAIL_UNAVAILABLE":"Emailing share links is temporarily unavailable. Create the link without email_to and send it yourself.","FROM_DOMAIN_MISMATCH":"The From address is not at this domain.","IDEMPOTENCY_KEY_CONFLICTS_WITH_ROW":"An `idempotency_key` on a batch row conflicts with the request key.","IMPORT_IN_PROGRESS":"Another contact import is running for this workspace.","IMPORT_NOT_FOUND":"Import not found.","IMPORT_TOO_LARGE":"The import file is over the size limit.","INVALID_CAPABILITIES":"At least one capability (sending or receiving) must be enabled.","INVALID_CONTACT_PROPERTY_VALUE":"A contact property value does not match the property type.","INVALID_CSV":"The first line must be a header with an \"email\" column.","INVALID_DATE":"A date is not valid ISO 8601.","INVALID_DATE_RANGE":"The date range is invalid (start after end).","INVALID_DATE_WINDOW":"The date window is invalid.","INVALID_FORMAT":"A path or query value is not in the expected format.","INVALID_FROM_ADDRESS":"The From address could not be parsed.","INVALID_SEGMENT_RULE":"The segment rule is invalid (`details.problems`).","INVALID_TIMEZONE":"The time zone is not a valid IANA name.","INVALID_ZONE":"The DNS zone is not one this domain belongs to.","MAIL_FROM_HOST_IN_USE":"The MAIL FROM host already has records that are not ours (`details.found`).","MAIL_FROM_NOT_SENDING":"A custom MAIL FROM needs the domain to send.","MAIL_HEADER_NOT_ALLOWED":"A custom header is not allowed, or its value is invalid (`details.headers`).","PROVIDER_ERROR":"The DNS provider returned an error.","PROVIDER_PERMISSION_DENIED":"The DNS provider token lacks permission to edit this zone.","PROVIDER_TOKEN_REJECTED":"The DNS provider rejected the token.","PROVIDER_UNAVAILABLE":"The DNS provider is unavailable; try again later.","PROVIDER_ZONE_NOT_FOUND":"The DNS provider has no zone for this domain.","RECIPIENT_LIMIT":"More than 50 recipients across `to`, `cc` and `bcc`.","RECIPIENT_SUPPRESSED":"The recipient is suppressed for this workspace or topic (`details.reason`).","REGION_NOT_AVAILABLE":"`region` is not the region this deployment sends from (`details.available`).","RESERVED_PROPERTY_KEY":"The property key is reserved.","SEGMENT_EXISTS":"A segment with this name already exists.","SEGMENT_LIMIT":"The workspace has the maximum number of segments.","SEGMENT_NOT_FOUND":"Segment not found.","SEGMENT_RULE_BASED":"Members of a rule segment follow its rule: change the contact or the rule instead.","SEGMENT_TYPE_FIXED":"A static segment cannot take a rule: create a rule segment instead.","SES_IDENTITY_DELETE_FAILED":"The sending identity could not be removed from the email provider; retry.","SHARE_LINK_NOT_FOUND":"This setup link does not exist, has expired or was revoked.","SMTP_AUTH_PARTIAL":"SMTP username and password must be set together.","SMTP_CONFIG_NOT_FOUND":"No SMTP override saved for this domain.","SMTP_PASSWORD_REQUIRED":"An SMTP password is required.","TEMPLATE_DATA_INVALID":"The render data does not match the template schema.","TEMPLATE_KIND_NOT_SENDABLE":"This template kind (a partial or layout) cannot be sent on its own.","TEMPLATE_NOT_FOUND":"No template with this name in this workspace.","TEMPLATE_RENDER_FAILED":"The template could not be rendered.","TLS_ENFORCED_NOT_AVAILABLE":"`tls: enforced` is not available yet.","TOPIC_EXISTS":"A topic with this name already exists.","TOPIC_LIMIT":"The workspace has the maximum number of topics.","TOPIC_NOT_FOUND":"Topic not found.","TRACKING_NOT_AVAILABLE":"Open and click tracking are not available yet.","UNKNOWN_CONTACT_PROPERTY":"The contact property is not defined; create it first.","UNSUBSCRIBE_LINK_REQUIRED":"A broadcast body must contain `{{{unsubscribe_url}}}`.","domain_not_verified_by_provider":"The From domain's DNS records have been broken for over 72 h, so it no longer sends.","from_domain_not_verified":"The From domain is not an active sending domain of this workspace (`details: { fqdn, reason }`).","no_default_sender":"No `from` and the workspace has no default sender.","sender_domain_not_in_workspace":"The address is not on a sending domain of this workspace (`details.fqdn`)."}}},"headers":{"X-RateLimit-Limit-short":{"description":"Requests allowed per second from this client IP (20).","schema":{"type":"integer"}},"X-RateLimit-Remaining-short":{"description":"Requests left in the current one-second window.","schema":{"type":"integer"}},"X-RateLimit-Reset-short":{"description":"Seconds until the one-second window resets.","schema":{"type":"integer"}},"X-RateLimit-Limit-long":{"description":"Requests allowed per minute from this client IP (600).","schema":{"type":"integer"}},"X-RateLimit-Remaining-long":{"description":"Requests left in the current one-minute window.","schema":{"type":"integer"}},"X-RateLimit-Reset-long":{"description":"Seconds until the one-minute window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying. Sent on every 429.","schema":{"type":"integer"}},"Retry-After-short":{"description":"Deprecated: read `Retry-After`. Seconds to wait, when the per-second IP limit tripped.","deprecated":true,"schema":{"type":"integer"}},"Retry-After-long":{"description":"Deprecated: read `Retry-After`. Seconds to wait, when the per-minute IP limit tripped.","deprecated":true,"schema":{"type":"integer"}},"RequestId":{"description":"The request's id: the inbound `X-Request-Id` when it is 1 to 128 characters of `A-Z a-z 0-9 . _ : -`, otherwise a fresh `req_...` id. Error bodies repeat it as `request_id`. Quote it when contacting support.","schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$","example":"req_6f1c2a9d4b7e4f0a8c3d2e1f0a9b8c7d"}}}},"x-webhooks":{"email.sent":{"post":{"summary":"The message was accepted and we are delivering it to the recipient's mail server.","description":"A `email.sent` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.sent` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSentEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.delivered":{"post":{"summary":"The recipient's mail server accepted the message.","description":"A `email.delivered` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.delivered` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDeliveredEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.delivery_delayed":{"post":{"summary":"Delivery is being retried after a temporary failure.","description":"A `email.delivery_delayed` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.delivery_delayed` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDeliveryDelayedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.bounced":{"post":{"summary":"The message bounced permanently; the address is suppressed.","description":"A `email.bounced` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.bounced` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailBouncedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.complained":{"post":{"summary":"The recipient marked the message as spam; the address is suppressed.","description":"A `email.complained` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.complained` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailComplainedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.failed":{"post":{"summary":"The message could not be sent because of an error; nothing was sent.","description":"A `email.failed` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.failed` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailFailedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.suppressed":{"post":{"summary":"A send was refused because the recipient is on the suppression list.","description":"A `email.suppressed` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.suppressed` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSuppressedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.skipped":{"post":{"summary":"A template send was skipped: it named no sender and the workspace has no default sender set.","description":"A `email.skipped` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.skipped` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSkippedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.scheduled":{"post":{"summary":"A message was scheduled for later (scheduled sending; not emitted yet).","description":"A `email.scheduled` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.scheduled` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailScheduledEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.canceled":{"post":{"summary":"A scheduled message was canceled (scheduled sending; not emitted yet).","description":"A `email.canceled` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.canceled` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailCanceledEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.opened":{"post":{"summary":"The recipient opened the message (open tracking; not emitted yet).","description":"A `email.opened` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.opened` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailOpenedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.clicked":{"post":{"summary":"The recipient clicked a link (click tracking; not emitted yet).","description":"A `email.clicked` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.clicked` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailClickedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"email.received":{"post":{"summary":"A mailbox received a message (inbound webhooks; not emitted yet).","description":"A `email.received` event (Email), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Email","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `email.received` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailReceivedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"domain.created":{"post":{"summary":"A domain was added to the workspace.","description":"A `domain.created` event (Domains), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Domains","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `domain.created` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainCreatedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"domain.updated":{"post":{"summary":"A domain's DNS records, signing status or health changed.","description":"A `domain.updated` event (Domains), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Domains","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `domain.updated` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainUpdatedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"domain.verified":{"post":{"summary":"A domain finished verification and can send.","description":"A `domain.verified` event (Domains), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Domains","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `domain.verified` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainVerifiedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"domain.deleted":{"post":{"summary":"A domain was removed.","description":"A `domain.deleted` event (Domains), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Domains","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `domain.deleted` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainDeletedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"suppression.added":{"post":{"summary":"An address was added to the suppression list (bounce, complaint or by hand).","description":"A `suppression.added` event (Suppressions), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Suppressions","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `suppression.added` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuppressionAddedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"suppression.removed":{"post":{"summary":"An address was removed from the suppression list.","description":"A `suppression.removed` event (Suppressions), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Suppressions","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `suppression.removed` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuppressionRemovedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"sending_defaults.updated":{"post":{"summary":"The workspace default sender was set, changed or cleared.","description":"A `sending_defaults.updated` event (Settings), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Settings","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `sending_defaults.updated` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendingDefaultsUpdatedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"contact.created":{"post":{"summary":"A contact was added (by the API, the dashboard, or an unsubscribe from someone who was not a contact).","description":"A `contact.created` event (Contacts), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Contacts","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `contact.created` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactCreatedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"contact.updated":{"post":{"summary":"A contact changed: its fields, its global unsubscribe, or its topic subscriptions (including through an unsubscribe link).","description":"A `contact.updated` event (Contacts), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Contacts","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `contact.updated` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactUpdatedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}},"contact.deleted":{"post":{"summary":"A contact was deleted.","description":"A `contact.deleted` event (Contacts), POSTed as JSON to every enabled endpoint subscribed to it and signed with the Standard Webhooks headers. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h.","tags":["outbound-webhooks"],"x-pc-webhook-category":"Contacts","parameters":[{"name":"webhook-id","in":"header","required":true,"description":"The event id: the same on every retry and replay, so dedupe on it. Part of the signed content.","schema":{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"},"example":"evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f"},{"name":"webhook-timestamp","in":"header","required":true,"description":"Unix seconds of this attempt. Part of the signed content; reject a delivery more than 5 minutes from your clock.","schema":{"type":"string","pattern":"^\\d+$"},"example":"1793869200"},{"name":"webhook-signature","in":"header","required":true,"description":"`v1,<base64 HMAC-SHA256 of \"<webhook-id>.<webhook-timestamp>.<raw body>\">`, keyed with the base64-decoded part of the endpoint's `whsec_` secret. During a secret rotation it carries one space-separated `v1,` entry per active secret; accept the delivery when any entry matches.","schema":{"type":"string"},"example":"v1,lkO4DTG3zOoxV5QD2PC5B41Sc8nqZNoh50NPrwnhJ5I="},{"name":"X-Mail-Signature","in":"header","required":false,"deprecated":true,"description":"Only to endpoints carried over from the previous webhook system (`legacy_signature: true`), until its sunset: `t=<unix>,v1=<hex HMAC-SHA256 of \"<unix>.<raw body>\">`, keyed with the UTF-8 bytes of the whole secret string. Verify `webhook-signature` instead.","schema":{"type":"string","pattern":"^t=\\d+,v1=[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The `contact.deleted` event. Verify the signature over the raw body before parsing it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDeletedEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Answer with any 2xx within 15 s to acknowledge it; anything else, or no answer, is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 24 h."}}}}},"x-pc-webhook-signing":{"scheme":"standard-webhooks","spec_url":"https://www.standardwebhooks.com","algorithm":"HMAC-SHA256","headers":{"id":"webhook-id","timestamp":"webhook-timestamp","signature":"webhook-signature"},"signed_content":"{webhook-id}.{webhook-timestamp}.{body}","signature_format":"v1,<base64>","secret_prefix":"whsec_","secret_key":"base64 decode of the part after `whsec_`; a secret without the prefix (minted before it) is used as its UTF-8 bytes","tolerance_seconds":300,"rotation":"space-separated `v1,` entries, one per active secret, current first","legacy":{"header":"X-Mail-Signature","format":"t=<unix>,v1=<hex>","signed_content":"{t}.{body}","secret_key":"UTF-8 bytes of the whole secret string","deprecated":true}}}