{
  "openapi": "3.1.0",
  "info": {
    "title": "Send & Retain API",
    "version": "1.1.0",
    "description": "Send transactional and marketing email, sync contacts, and emit events that drive automations. One recipient per send — there are no bulk campaigns. Authenticate with a per-project API key (`aem_…`).\n\n**Every response** — success or error — carries `X-Request-Id`. It echoes your own `X-Request-Id` when you send a sane one (letters, digits, `.`, `_`, `-`, up to 128 chars) and is otherwise generated. Errors repeat it in the body as `request_id`, so pasting the JSON into a support request is enough to find the call.\n\n**Errors** are always `{ error: { code, message } }`. `code` is a stable identifier to branch on; `message` is human-readable and safe to log but not to branch on. The HTTP status is derived from `code`, never inferred from the message.\n\n**Rate limits.** Every response carries `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` (seconds until the window refills) and `RateLimit-Policy`; a 429 adds `Retry-After` and `retry_after_ms`. Treat these as a best-effort backstop against runaway loops, not a quota: the limiter is per-instance, so the effective ceiling across a horizontally-scaled deployment is higher than the advertised number and is not currently enforced globally.\n\n**The send path is not on the per-key limiter.** `POST /emails`, `POST /emails/batch`, `PATCH` / `DELETE /emails/{id}` and `POST /events` carry no `RateLimit-*` headers: they are governed by the project's sending caps (`429` with code `daily_cap` / `monthly_cap` — a quota, not a throttle; branch on the code) and a per-provider throttle that queues rather than refuses.\n\n**Idempotency.** Every create — sends included — takes an `Idempotency-Key` header (1–256 chars, kept 24 hours). The same key and body replays the first success with `Idempotency-Replay: true`; the same key with a different body, or while the first request is still running, is `409 conflict`.\n\n**Lists** answer `{ object: \"list\", data, has_more, next_cursor }`. Pass `next_cursor` back as `?cursor=` until `has_more` is false. `?before=` still works where it existed and is deprecated.\n\n**Webhooks.** The events we POST to your endpoints are documented under `webhooks`, one schema per event type, discriminated on `type`.",
    "x-operation-digest": "9cc8aa0e6b29",
    "x-content-digest": "3c9ac6e3304a",
    "x-generated-from": "lib/openapi/registry.ts"
  },
  "servers": [
    {
      "url": "https://sendandretain.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Emails",
      "description": "Send email, list sent messages, and read a message's status + event timeline."
    },
    {
      "name": "Contacts",
      "description": "Upsert, list, read, and delete the people you send to."
    },
    {
      "name": "Events",
      "description": "Emit events that trigger automations."
    },
    {
      "name": "Suppressions",
      "description": "Read and manage the do-not-send list."
    },
    {
      "name": "Templates",
      "description": "Author, render, test and publish react.email templates. Published versions are immutable — every edit creates a new draft."
    },
    {
      "name": "Automations",
      "description": "Create and edit event-triggered automations. Automations are always created paused; enabling one is a separate call."
    },
    {
      "name": "Audience",
      "description": "Segments — who gets grouped for a send."
    },
    {
      "name": "Setup",
      "description": "Sending infrastructure: domains, senders, provider webhooks. Requires an `admin`-scope key. Provider API keys are never settable here."
    },
    {
      "name": "Webhooks",
      "description": "Deliver email events to your own HTTPS endpoints, so you don't have to poll. Signed with the [Standard Webhooks](https://www.standardwebhooks.com) scheme — `webhook-id`, `webhook-timestamp`, `webhook-signature` — which any off-the-shelf verifier understands. Delivery is at-least-once and unordered: dedupe on `webhook-id`, order on `occurred_at`. Requires an `admin`-scope key."
    },
    {
      "name": "Metrics",
      "description": "Delivery funnel, daily trends, and worker-queue health."
    },
    {
      "name": "Settings",
      "description": "Project guardrails (kill switch, daily cap) and the company brand kit."
    }
  ],
  "webhooks": {
    "email.sent": {
      "post": {
        "operationId": "webhook_email_sent",
        "summary": "email.sent",
        "description": "The provider accepted the message.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailSent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.delivered": {
      "post": {
        "operationId": "webhook_email_delivered",
        "summary": "email.delivered",
        "description": "The recipient's mail server accepted the message.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailDelivered"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.delivery_delayed": {
      "post": {
        "operationId": "webhook_email_delivery_delayed",
        "summary": "email.delivery_delayed",
        "description": "Delivery is being retried by the provider.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailDeliveryDelayed"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.bounced": {
      "post": {
        "operationId": "webhook_email_bounced",
        "summary": "email.bounced",
        "description": "The message bounced. Hard bounces suppress the address automatically.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailBounced"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.complained": {
      "post": {
        "operationId": "webhook_email_complained",
        "summary": "email.complained",
        "description": "The recipient marked the message as spam. The address is suppressed permanently.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailComplained"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.opened": {
      "post": {
        "operationId": "webhook_email_opened",
        "summary": "email.opened",
        "description": "The recipient opened the message (requires open tracking).\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailOpened"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.clicked": {
      "post": {
        "operationId": "webhook_email_clicked",
        "summary": "email.clicked",
        "description": "The recipient clicked a tracked link (requires click tracking).\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailClicked"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.unsubscribed": {
      "post": {
        "operationId": "webhook_email_unsubscribed",
        "summary": "email.unsubscribed",
        "description": "The recipient unsubscribed.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailUnsubscribed"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.suppressed": {
      "post": {
        "operationId": "webhook_email_suppressed",
        "summary": "email.suppressed",
        "description": "The send was refused because the address is suppressed.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailSuppressed"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.failed": {
      "post": {
        "operationId": "webhook_email_failed",
        "summary": "email.failed",
        "description": "The send failed permanently after retries.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailFailed"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "email.canceled": {
      "post": {
        "operationId": "webhook_email_canceled",
        "summary": "email.canceled",
        "description": "A scheduled send was canceled.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventEmailCanceled"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    },
    "webhook.test": {
      "post": {
        "operationId": "webhook_webhook_test",
        "summary": "webhook.test",
        "description": "Sent by `POST /api/v1/webhooks/{id}/test`. Carries no message.\n\nSigned with [Standard Webhooks](https://www.standardwebhooks.com). At-least-once and unordered. Payloads are at most 64 KB. Answer any 2xx within 10 seconds; anything else is retried on the published curve.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery id. Identical across retries — dedupe on it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds. Reject anything more than 5 minutes from now (replay protection).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "Space-separated `v1,<base64 HMAC-SHA256>` signatures of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64 part of your `whsec_` secret. Two appear during a secret rotation's grace window; accept either. Verify against the RAW body, before parsing.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEventWebhookTest"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted. Any 2xx stops retries."
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "X-Request-Id": {
        "description": "Unique id for this request — echoes yours when you send a valid one (`[A-Za-z0-9._-]{1,128}`). Errors repeat it in the body as `request_id`; quote it in a support request.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit-Limit": {
        "description": "Requests allowed per window for this key and bucket.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Remaining": {
        "description": "Requests left in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Reset": {
        "description": "Seconds until the window refills.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Policy": {
        "description": "The window, e.g. `120;w=60`.",
        "schema": {
          "type": "string"
        }
      },
      "Retry-After": {
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer"
        }
      },
      "Idempotency-Replay": {
        "description": "`true` when this response replays the result of an earlier request with the same `Idempotency-Key`. No new work was done.",
        "schema": {
          "type": "string",
          "enum": [
            "true"
          ]
        }
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Makes a retry safe (1–256 chars, kept 24 hours). The same key with the same body replays the first success with `Idempotency-Replay: true`; the same key with a different body, or while the first request is still running, is `409 conflict`. A failed request releases its key. Use a value tied to the thing you are creating, e.g. `onboarding/user_42`.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 256
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "Opaque — pass the previous page's `next_cursor` to fetch the next page. A malformed cursor is refused, never treated as page one.",
        "schema": {
          "type": "string"
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from the dashboard under Settings → API keys, sent as `Authorization: Bearer aem_…`.\n\nAuthorization has two independent axes.\n\nThe **scope** is ranked — a key satisfies any requirement at or below its own tier:\n\n- **`read`** — see messages, contacts and metrics. Changes nothing, and cannot send.\n- **`write`** — everything `read` does, plus managing templates, contacts, automations, segments and suppressions. This is what editing a template needs.\n- **`admin`** — everything `write` does, plus sending *configuration*: domains, senders, webhook registration, kill switch, daily cap, brand.\n\nThere is no `approve` scope. It was a rung once; it is not one now, and a key requested with it is rejected.\n\nThe **approval grant** (`can_approve`) is a separate boolean, not a rung. Delivering mail to a real inbox needs `write` **and** the grant. Keeping them on separate axes is what makes the review gate a control rather than a convention: a key that may propose is not automatically a key that may approve its own proposal.\n\nGive your application the lowest tier that works. Most need `write` **and** the grant — the dashboard mints that combination as **Send + manage**; **Manage only** is the same rung with the grant withheld."
      }
    },
    "schemas": {
      "UpdateAutomation___schema0": {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "enum": [
              "and",
              "or"
            ]
          },
          "conditions": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                    },
                    "op": {
                      "default": "eq",
                      "type": "string",
                      "enum": [
                        "eq",
                        "neq",
                        "exists",
                        "not_exists",
                        "in",
                        "gt",
                        "lt",
                        "contains",
                        "within_days",
                        "older_than_days"
                      ]
                    },
                    "value": {}
                  },
                  "required": [
                    "path"
                  ]
                },
                {
                  "$ref": "#/components/schemas/UpdateAutomation___schema0"
                }
              ]
            }
          }
        },
        "required": [
          "op",
          "conditions"
        ]
      },
      "UpdateStep___schema0": {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "enum": [
              "and",
              "or"
            ]
          },
          "conditions": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                    },
                    "op": {
                      "default": "eq",
                      "type": "string",
                      "enum": [
                        "eq",
                        "neq",
                        "exists",
                        "not_exists",
                        "in",
                        "gt",
                        "lt",
                        "contains",
                        "within_days",
                        "older_than_days"
                      ]
                    },
                    "value": {}
                  },
                  "required": [
                    "path"
                  ]
                },
                {
                  "$ref": "#/components/schemas/UpdateStep___schema0"
                }
              ]
            }
          }
        },
        "required": [
          "op",
          "conditions"
        ]
      },
      "CreateAutomation___schema0": {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "enum": [
              "and",
              "or"
            ]
          },
          "conditions": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                    },
                    "op": {
                      "default": "eq",
                      "type": "string",
                      "enum": [
                        "eq",
                        "neq",
                        "exists",
                        "not_exists",
                        "in",
                        "gt",
                        "lt",
                        "contains",
                        "within_days",
                        "older_than_days"
                      ]
                    },
                    "value": {}
                  },
                  "required": [
                    "path"
                  ]
                },
                {
                  "$ref": "#/components/schemas/CreateAutomation___schema0"
                }
              ]
            }
          }
        },
        "required": [
          "op",
          "conditions"
        ]
      },
      "CreateAutomation___schema1": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send"
              },
              "templateSlug": {
                "type": "string",
                "minLength": 1
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "propsOverrides": {
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {}
              },
              "subject": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              "previewText": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              }
            },
            "required": [
              "type",
              "templateSlug",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "delay"
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 60,
                "maximum": 9007199254740991,
                "description": "How long to wait before continuing, in seconds (min 60s). Weekly = 604800."
              }
            },
            "required": [
              "type",
              "delaySeconds"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "wait_for_event"
              },
              "eventName": {
                "type": "string",
                "minLength": 1,
                "maxLength": 120,
                "description": "contact_event name that resumes the run."
              },
              "timeoutSeconds": {
                "type": "integer",
                "minimum": 60,
                "maximum": 7776000,
                "description": "Give up waiting after this many seconds (60s .. 90d) and continue."
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              }
            },
            "required": [
              "type",
              "eventName",
              "timeoutSeconds",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "set_attribute"
              },
              "attributes": {
                "description": "Attributes to shallow-merge onto the contact.",
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {}
              },
              "addTags": {
                "description": "Tags to add — segments filtering on contact.tags follow automatically.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 60
                }
              },
              "removeTags": {
                "description": "Tags to remove.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 60
                }
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              }
            },
            "required": [
              "type",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "webhook"
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Public HTTPS endpoint to POST to."
              },
              "method": {
                "default": "POST",
                "type": "string",
                "enum": [
                  "POST",
                  "PUT"
                ]
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              }
            },
            "required": [
              "type",
              "url",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "exit"
              },
              "label": {
                "description": "Shown on the canvas and in exit counts.",
                "type": "string",
                "maxLength": 60
              },
              "delaySeconds": {
                "default": 0,
                "description": "Exits are immediate — put the wait on the step before.",
                "type": "integer",
                "minimum": 0,
                "maximum": 0
              }
            },
            "required": [
              "type"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "unsubscribe"
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              }
            },
            "required": [
              "type",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "branch"
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              },
              "filter": {
                "description": "Evaluated against contact attributes ⊕ the trigger event.",
                "anyOf": [
                  {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string",
                          "minLength": 1,
                          "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                        },
                        "op": {
                          "default": "eq",
                          "type": "string",
                          "enum": [
                            "eq",
                            "neq",
                            "exists",
                            "not_exists",
                            "in",
                            "gt",
                            "lt",
                            "contains",
                            "within_days",
                            "older_than_days"
                          ]
                        },
                        "value": {}
                      },
                      "required": [
                        "path"
                      ]
                    }
                  },
                  {
                    "$ref": "#/components/schemas/CreateAutomation___schema0"
                  }
                ]
              },
              "yes": {
                "description": "Steps for contacts matching the filter.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CreateAutomation___schema1"
                }
              },
              "no": {
                "description": "Steps for everyone else.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CreateAutomation___schema1"
                }
              },
              "branches": {
                "description": "Ordered arms — the first matching filter wins.",
                "minItems": 1,
                "maxItems": 8,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "type": "string",
                      "pattern": "^[a-z0-9][a-z0-9_-]{0,39}$"
                    },
                    "label": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "filter": {
                      "anyOf": [
                        {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "path": {
                                "type": "string",
                                "minLength": 1,
                                "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                              },
                              "op": {
                                "default": "eq",
                                "type": "string",
                                "enum": [
                                  "eq",
                                  "neq",
                                  "exists",
                                  "not_exists",
                                  "in",
                                  "gt",
                                  "lt",
                                  "contains",
                                  "within_days",
                                  "older_than_days"
                                ]
                              },
                              "value": {}
                            },
                            "required": [
                              "path"
                            ]
                          }
                        },
                        {
                          "$ref": "#/components/schemas/CreateAutomation___schema0"
                        }
                      ]
                    },
                    "steps": {
                      "maxItems": 50,
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CreateAutomation___schema1"
                      }
                    }
                  },
                  "required": [
                    "key",
                    "filter"
                  ]
                }
              },
              "elseSteps": {
                "description": "Steps for contacts matching no arm.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CreateAutomation___schema1"
                }
              },
              "ifMatch": {
                "type": "string",
                "enum": [
                  "continue",
                  "exit"
                ]
              },
              "ifNoMatch": {
                "type": "string",
                "enum": [
                  "continue",
                  "exit"
                ]
              }
            },
            "required": [
              "type",
              "delaySeconds"
            ]
          }
        ]
      },
      "AddAutomationSteps___schema0": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send"
              },
              "templateSlug": {
                "type": "string",
                "minLength": 1
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "propsOverrides": {
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {}
              },
              "subject": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              "previewText": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              }
            },
            "required": [
              "type",
              "templateSlug",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "delay"
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 60,
                "maximum": 9007199254740991,
                "description": "How long to wait before continuing, in seconds (min 60s). Weekly = 604800."
              }
            },
            "required": [
              "type",
              "delaySeconds"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "wait_for_event"
              },
              "eventName": {
                "type": "string",
                "minLength": 1,
                "maxLength": 120,
                "description": "contact_event name that resumes the run."
              },
              "timeoutSeconds": {
                "type": "integer",
                "minimum": 60,
                "maximum": 7776000,
                "description": "Give up waiting after this many seconds (60s .. 90d) and continue."
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              }
            },
            "required": [
              "type",
              "eventName",
              "timeoutSeconds",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "set_attribute"
              },
              "attributes": {
                "description": "Attributes to shallow-merge onto the contact.",
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {}
              },
              "addTags": {
                "description": "Tags to add — segments filtering on contact.tags follow automatically.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 60
                }
              },
              "removeTags": {
                "description": "Tags to remove.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 60
                }
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              }
            },
            "required": [
              "type",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "webhook"
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Public HTTPS endpoint to POST to."
              },
              "method": {
                "default": "POST",
                "type": "string",
                "enum": [
                  "POST",
                  "PUT"
                ]
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              }
            },
            "required": [
              "type",
              "url",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "exit"
              },
              "label": {
                "description": "Shown on the canvas and in exit counts.",
                "type": "string",
                "maxLength": 60
              },
              "delaySeconds": {
                "default": 0,
                "description": "Exits are immediate — put the wait on the step before.",
                "type": "integer",
                "minimum": 0,
                "maximum": 0
              }
            },
            "required": [
              "type"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "unsubscribe"
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              }
            },
            "required": [
              "type",
              "delaySeconds"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "branch"
              },
              "delaySeconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991,
                "description": "Delay before this step runs (0 = immediate). Weekly = 604800."
              },
              "sendWindow": {
                "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                "type": "object",
                "properties": {
                  "days": {
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 7
                    }
                  },
                  "startHour": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 23
                  },
                  "endHour": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "timezone": {
                    "type": "string"
                  }
                }
              },
              "filter": {
                "description": "Evaluated against contact attributes ⊕ the trigger event.",
                "anyOf": [
                  {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string",
                          "minLength": 1,
                          "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                        },
                        "op": {
                          "default": "eq",
                          "type": "string",
                          "enum": [
                            "eq",
                            "neq",
                            "exists",
                            "not_exists",
                            "in",
                            "gt",
                            "lt",
                            "contains",
                            "within_days",
                            "older_than_days"
                          ]
                        },
                        "value": {}
                      },
                      "required": [
                        "path"
                      ]
                    }
                  },
                  {
                    "$ref": "#/components/schemas/AddAutomationSteps___schema1"
                  }
                ]
              },
              "yes": {
                "description": "Steps for contacts matching the filter.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AddAutomationSteps___schema0"
                }
              },
              "no": {
                "description": "Steps for everyone else.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AddAutomationSteps___schema0"
                }
              },
              "branches": {
                "description": "Ordered arms — the first matching filter wins.",
                "minItems": 1,
                "maxItems": 8,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "type": "string",
                      "pattern": "^[a-z0-9][a-z0-9_-]{0,39}$"
                    },
                    "label": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "filter": {
                      "anyOf": [
                        {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "path": {
                                "type": "string",
                                "minLength": 1,
                                "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                              },
                              "op": {
                                "default": "eq",
                                "type": "string",
                                "enum": [
                                  "eq",
                                  "neq",
                                  "exists",
                                  "not_exists",
                                  "in",
                                  "gt",
                                  "lt",
                                  "contains",
                                  "within_days",
                                  "older_than_days"
                                ]
                              },
                              "value": {}
                            },
                            "required": [
                              "path"
                            ]
                          }
                        },
                        {
                          "$ref": "#/components/schemas/AddAutomationSteps___schema1"
                        }
                      ]
                    },
                    "steps": {
                      "maxItems": 50,
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AddAutomationSteps___schema0"
                      }
                    }
                  },
                  "required": [
                    "key",
                    "filter"
                  ]
                }
              },
              "elseSteps": {
                "description": "Steps for contacts matching no arm.",
                "maxItems": 50,
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AddAutomationSteps___schema0"
                }
              },
              "ifMatch": {
                "type": "string",
                "enum": [
                  "continue",
                  "exit"
                ]
              },
              "ifNoMatch": {
                "type": "string",
                "enum": [
                  "continue",
                  "exit"
                ]
              }
            },
            "required": [
              "type",
              "delaySeconds"
            ]
          }
        ]
      },
      "AddAutomationSteps___schema1": {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "enum": [
              "and",
              "or"
            ]
          },
          "conditions": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                    },
                    "op": {
                      "default": "eq",
                      "type": "string",
                      "enum": [
                        "eq",
                        "neq",
                        "exists",
                        "not_exists",
                        "in",
                        "gt",
                        "lt",
                        "contains",
                        "within_days",
                        "older_than_days"
                      ]
                    },
                    "value": {}
                  },
                  "required": [
                    "path"
                  ]
                },
                {
                  "$ref": "#/components/schemas/AddAutomationSteps___schema1"
                }
              ]
            }
          }
        },
        "required": [
          "op",
          "conditions"
        ]
      },
      "ListEnvelope": {
        "type": "object",
        "required": [
          "object",
          "data",
          "has_more",
          "next_cursor"
        ],
        "description": "Every list answers this shape. Keep requesting with `?cursor=<next_cursor>` until `has_more` is false.",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "list"
            ]
          },
          "data": {
            "type": "array",
            "items": {}
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "WebhookMessage": {
        "type": "object",
        "description": "The message the event is about.",
        "required": [
          "id",
          "to",
          "from",
          "status",
          "source",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "to": {
            "type": "string"
          },
          "from": {
            "type": "string"
          },
          "subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "template": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "tags": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "required": [
                "name",
                "value"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              }
            }
          },
          "source": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "WebhookEventEmailSent": {
        "type": "object",
        "description": "The provider accepted the message.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.sent"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {}
              }
            }
          }
        }
      },
      "WebhookEventEmailDelivered": {
        "type": "object",
        "description": "The recipient's mail server accepted the message.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.delivered"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {}
              }
            }
          }
        }
      },
      "WebhookEventEmailDeliveryDelayed": {
        "type": "object",
        "description": "Delivery is being retried by the provider.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.delivery_delayed"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {
                  "reason": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "WebhookEventEmailBounced": {
        "type": "object",
        "description": "The message bounced. Hard bounces suppress the address automatically.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.bounced"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {
                  "type": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  },
                  "sub_type": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  },
                  "diagnostic": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "WebhookEventEmailComplained": {
        "type": "object",
        "description": "The recipient marked the message as spam. The address is suppressed permanently.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.complained"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {
                  "feedback_type": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "WebhookEventEmailOpened": {
        "type": "object",
        "description": "The recipient opened the message (requires open tracking).",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.opened"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {
                  "user_agent": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  },
                  "ip": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "WebhookEventEmailClicked": {
        "type": "object",
        "description": "The recipient clicked a tracked link (requires click tracking).",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.clicked"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {
                  "link": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  },
                  "user_agent": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  },
                  "ip": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "WebhookEventEmailUnsubscribed": {
        "type": "object",
        "description": "The recipient unsubscribed.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.unsubscribed"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {
                  "scope": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "WebhookEventEmailSuppressed": {
        "type": "object",
        "description": "The send was refused because the address is suppressed.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.suppressed"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {
                  "reason": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "WebhookEventEmailFailed": {
        "type": "object",
        "description": "The send failed permanently after retries.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.failed"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {
                  "reason": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  },
                  "attempts": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "WebhookEventEmailCanceled": {
        "type": "object",
        "description": "A scheduled send was canceled.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "email.canceled"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WebhookMessage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {}
              }
            }
          }
        }
      },
      "WebhookEventWebhookTest": {
        "type": "object",
        "description": "Sent by `POST /api/v1/webhooks/{id}/test`. Carries no message.",
        "required": [
          "id",
          "type",
          "version",
          "created_at",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery id — also sent as `webhook-id`. Dedupe on it."
          },
          "type": {
            "type": "string",
            "enum": [
              "webhook.test"
            ]
          },
          "version": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When we queued it."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened. Order on this, never on arrival."
          },
          "data": {
            "type": "object",
            "required": [
              "event_id",
              "message",
              "detail"
            ],
            "properties": {
              "event_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "message": {
                "type": "null"
              },
              "detail": {
                "type": "object",
                "description": "Provider detail, normalised. Fields are present only when the provider reported them.",
                "properties": {}
              }
            }
          }
        }
      },
      "WebhookEvent": {
        "description": "Any event we deliver. Discriminate on `type`.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/WebhookEventEmailSent"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailDelivered"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailDeliveryDelayed"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailBounced"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailComplained"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailOpened"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailClicked"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailUnsubscribed"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailSuppressed"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailFailed"
          },
          {
            "$ref": "#/components/schemas/WebhookEventEmailCanceled"
          },
          {
            "$ref": "#/components/schemas/WebhookEventWebhookTest"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "email.sent": "#/components/schemas/WebhookEventEmailSent",
            "email.delivered": "#/components/schemas/WebhookEventEmailDelivered",
            "email.delivery_delayed": "#/components/schemas/WebhookEventEmailDeliveryDelayed",
            "email.bounced": "#/components/schemas/WebhookEventEmailBounced",
            "email.complained": "#/components/schemas/WebhookEventEmailComplained",
            "email.opened": "#/components/schemas/WebhookEventEmailOpened",
            "email.clicked": "#/components/schemas/WebhookEventEmailClicked",
            "email.unsubscribed": "#/components/schemas/WebhookEventEmailUnsubscribed",
            "email.suppressed": "#/components/schemas/WebhookEventEmailSuppressed",
            "email.failed": "#/components/schemas/WebhookEventEmailFailed",
            "email.canceled": "#/components/schemas/WebhookEventEmailCanceled",
            "webhook.test": "#/components/schemas/WebhookEventWebhookTest"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "description": "Every 4xx/5xx response uses this envelope.",
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable, machine-readable error code.",
                "enum": [
                  "unauthorized",
                  "forbidden",
                  "invalid_request",
                  "not_found",
                  "conflict",
                  "proposal_rejected",
                  "rate_limited",
                  "upstream_error",
                  "internal",
                  "template_not_found",
                  "template_not_published",
                  "suppressed",
                  "sends_paused",
                  "daily_cap",
                  "monthly_cap",
                  "provider_error",
                  "validation_error"
                ],
                "examples": [
                  "invalid_request"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation.",
                "examples": [
                  "Body must be JSON."
                ]
              },
              "message_id": {
                "type": "string",
                "description": "Present on send failures that were still logged (e.g. suppressed)."
              },
              "request_id": {
                "type": "string",
                "description": "Echoes the `X-Request-Id` header. Present on every error. Quote it in a support request.",
                "examples": [
                  "req_8fK2mQ"
                ]
              },
              "required_scope": {
                "type": "string",
                "enum": [
                  "read",
                  "write",
                  "admin"
                ],
                "description": "On a 403 refused at the rung: the tier this endpoint needs."
              },
              "required_grant": {
                "type": "string",
                "enum": [
                  "approve"
                ],
                "description": "On a 403 refused at the grant: the key's rung was sufficient but it may not take the irreversible action. Not a tier — branch on this separately from `required_scope`."
              },
              "key_scope": {
                "type": "string",
                "enum": [
                  "read",
                  "write",
                  "admin"
                ],
                "description": "On a 403: the tier the calling key actually holds."
              }
            }
          }
        }
      },
      "SendResult": {
        "type": "object",
        "required": [
          "id",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Message id — use it with GET /api/v1/emails/{id}.",
            "examples": [
              "msg_3aF9c1"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "sent",
              "queued",
              "scheduled"
            ],
            "description": "`sent` (delivered to provider synchronously), `queued` (throttled to the worker), or `scheduled`.",
            "examples": [
              "sent"
            ]
          },
          "deduplicated": {
            "type": "boolean",
            "description": "Present and true when a matching Idempotency-Key replayed a prior send."
          }
        }
      },
      "MessageStatus": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": [
              "msg_3aF9c1"
            ]
          },
          "to": {
            "type": "string",
            "examples": [
              "jane@acme.com"
            ]
          },
          "from": {
            "type": "string",
            "examples": [
              "hello@acme.com"
            ]
          },
          "subject": {
            "type": "string",
            "examples": [
              "Welcome to Acme"
            ]
          },
          "template": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "welcome"
            ]
          },
          "status": {
            "type": "string",
            "description": "Latest status on the delivery ladder.",
            "examples": [
              "delivered"
            ]
          },
          "last_event": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type of the newest event in `events`, or null before the first.",
            "examples": [
              "delivered"
            ]
          },
          "source": {
            "type": "string",
            "examples": [
              "api"
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "suppressed_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "provider": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "resend"
            ]
          },
          "provider_message_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "ab_variant": {
            "type": [
              "string",
              "null"
            ]
          },
          "scheduled_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "events": {
            "type": "array",
            "description": "Provider events for this message, oldest first (max 100).",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "examples": [
                    "delivered"
                  ]
                },
                "provider": {
                  "type": "string",
                  "examples": [
                    "resend"
                  ]
                },
                "occurred_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "ContactResult": {
        "type": "object",
        "required": [
          "id",
          "created"
        ],
        "properties": {
          "id": {
            "type": "string",
            "examples": [
              "ct_7Kd2"
            ]
          },
          "created": {
            "type": "boolean",
            "description": "true if a new contact was created, false if an existing one was updated."
          }
        }
      },
      "EventResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": [
              "ev_5m2P"
            ]
          },
          "enrolled": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ids of automations the contact was enrolled into by this event.",
            "examples": [
              [
                "auto_win_back"
              ]
            ]
          },
          "exited_runs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ids of in-flight automation runs this event caused to exit."
          },
          "skipped": {
            "type": "array",
            "description": "Automations that trigger on this event but declined this contact, and why. An empty `enrolled` with an empty `skipped` means no automation listens to this event name at all — the two cases look identical otherwise.",
            "items": {
              "type": "object",
              "properties": {
                "automation_id": {
                  "type": "string"
                },
                "reason": {
                  "type": "string",
                  "enum": [
                    "filtered",
                    "guarded",
                    "suppressed",
                    "exclusive",
                    "no_steps",
                    "already_running"
                  ],
                  "description": "`filtered` — the trigger filter excluded this contact. `guarded` — they have already been through this automation. `suppressed` — they opted out. `exclusive` — a higher-priority exclusive automation took them. `no_steps` — the automation has no steps. `already_running` — a run is already in flight."
                }
              }
            }
          },
          "deduplicated": {
            "type": "boolean",
            "description": "Present and true when dedupe_key matched a prior event."
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/emails": {
      "post": {
        "operationId": "sendEmail",
        "tags": [
          "Emails"
        ],
        "summary": "Send an email",
        "description": "Queues a send to one recipient from a published template. Returns `202` with a message id once the send is durably recorded — never waiting on the provider, so this is safe to call from inside your own user-facing request. Address verification, rendering and provider dispatch happen in the background, exactly as they do behind SendGrid's `202 Accepted` and Resend's immediate id.\n\nProblems with the REQUEST still come back right away as a 4xx: an unknown or unpublished template, no verified sender, a suppressed or undeliverable recipient, a paused project, a cap. What moves is the delivery itself.\n\nFollow a message with `GET /api/v1/emails/{id}`, or subscribe to your provider's webhooks. Pass an `Idempotency-Key` header to make retries safe.\n\nRequires a `write`-scope key.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Unique per logical send (≤256 chars). A repeat returns the original result with `deduplicated: true`.",
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "example": "welcome-jane-2026-07-20"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "to": {
                    "type": "string",
                    "format": "email",
                    "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "description": "Recipient email address. Single recipient — there are no bulk sends.",
                    "examples": [
                      "jane@acme.com"
                    ]
                  },
                  "cc": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "email",
                        "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                      },
                      {
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "email",
                          "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                        }
                      }
                    ],
                    "description": "Carbon-copy recipient(s) of the same message — a string or array. Not a way to bulk-send.",
                    "examples": [
                      "manager@acme.com"
                    ]
                  },
                  "bcc": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "email",
                        "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                      },
                      {
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "email",
                          "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                        }
                      }
                    ],
                    "description": "Blind-carbon-copy recipient(s) — a string or array.",
                    "examples": [
                      [
                        "ops@acme.com"
                      ]
                    ]
                  },
                  "template": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Slug of a published template in this project.",
                    "examples": [
                      "welcome"
                    ]
                  },
                  "props": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "Values for the template's variables.",
                    "examples": [
                      {
                        "firstName": "Jane",
                        "plan": "Pro"
                      }
                    ]
                  },
                  "locale": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 35,
                    "description": "Deliver a published translation for this locale (e.g. `fr`, `pt-BR`); falls back to the base language when no translation exists.",
                    "examples": [
                      "fr"
                    ]
                  },
                  "from": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 320,
                    "description": "Sender, as `Name <addr@domain>` or a bare address. The address must be on a verified sending domain in this project. Omit to use the project's default sender.",
                    "examples": [
                      "Acme <hello@acme.com>"
                    ]
                  },
                  "reply_to": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "email",
                        "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                      },
                      {
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "email",
                          "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                        }
                      }
                    ],
                    "description": "Reply-To address(es) — a string or array.",
                    "examples": [
                      "support@acme.com"
                    ]
                  },
                  "headers": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 128
                    },
                    "additionalProperties": {
                      "type": "string",
                      "maxLength": 998
                    },
                    "description": "Custom email headers. Reserved headers (List-Unsubscribe, Idempotency-Key, Cc/Bcc/Reply-To) are rejected.",
                    "examples": [
                      {
                        "X-Entity-Ref-ID": "ord_991"
                      }
                    ]
                  },
                  "tags": {
                    "maxItems": 10,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 256
                        },
                        "value": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 256
                        }
                      },
                      "required": [
                        "name",
                        "value"
                      ]
                    },
                    "description": "Up to 10 {name,value} metadata tags, forwarded to the provider for analytics.",
                    "examples": [
                      [
                        {
                          "name": "category",
                          "value": "receipt"
                        }
                      ]
                    ]
                  },
                  "scheduled_at": {
                    "type": "string",
                    "minLength": 1,
                    "description": "ISO 8601 timestamp, or natural language like `in 2 hours` / `tomorrow 9am`. A future value schedules the send via the worker. Cannot be combined with attachments. Manage with PATCH (reschedule) / DELETE (cancel).",
                    "examples": [
                      "2026-08-01T09:00:00Z"
                    ]
                  },
                  "attachments": {
                    "maxItems": 10,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "filename": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 255
                        },
                        "content": {
                          "type": "string",
                          "minLength": 1
                        },
                        "content_type": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "filename",
                        "content"
                      ]
                    },
                    "description": "Up to 10 attachments (base64 content). Total ≤ ~5 MB. Cannot be combined with scheduled_at."
                  }
                },
                "required": [
                  "to",
                  "template"
                ]
              },
              "example": {
                "to": "jane@acme.com",
                "template": "welcome",
                "props": {
                  "firstName": "Jane"
                },
                "from": "Acme <hello@acme.com>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay — the `Idempotency-Key` matched a send we already accepted. Carries that send's current status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResult"
                },
                "example": {
                  "id": "msg_3aF9c1",
                  "status": "sent",
                  "deduplicated": true
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "202": {
            "description": "Accepted. The message is recorded and will be delivered by the worker — `queued` now, or `scheduled` when you passed a future `scheduled_at`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResult"
                },
                "example": {
                  "id": "msg_3aF9c1",
                  "status": "queued"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key's authorization is short on one of two axes: it is below `write`, or it lacks the approval grant. The grant is a separate boolean, not a rung above `write` — a key can hold `admin` and still be refused here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires the send grant (deliver mail to a real inbox) — this key does not have it.",
                    "required_grant": "approve",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template with that slug in this project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "template_not_found",
                    "message": "No template 'welcome' in this project."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "Template not published, or sends are paused (kill switch).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "template_not_published",
                    "message": "Template 'welcome' has no published version."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "422": {
            "description": "Recipient is on the suppression list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "suppressed",
                    "message": "jane@acme.com is suppressed (bounce)."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Daily or monthly send cap reached for this project (provider plan or project setting).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "daily_cap",
                    "message": "Send cap reached (100/day)."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          },
          "502": {
            "description": "The email provider rejected the send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "provider_error",
                    "message": "Provider rejected the message."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "x-requires-approval": true
      },
      "get": {
        "operationId": "listEmails",
        "tags": [
          "Emails"
        ],
        "summary": "List sent emails",
        "description": "Lists messages newest-first. Filter by `status` or recipient `to`; page with `limit` + `before` (an ISO `created_at`). Requires a `write`-scope key.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by delivery status.",
            "schema": {
              "type": "string"
            },
            "example": "delivered"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Substring match on the recipient address.",
            "schema": {
              "type": "string"
            },
            "example": "jane@"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size (1–100, default 50).",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "Deprecated — use `cursor`. ISO 8601 `created_at`: rows older than this.",
            "schema": {
              "type": "string"
            },
            "example": "2026-07-20T00:00:00Z",
            "deprecated": true,
            "x-sunset": "2027-04-05T00:00:00.000Z",
            "x-deprecation-link": "https://sendandretain.com/docs/api/pagination",
            "x-replaced-by": "?cursor="
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of messages.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MessageStatus"
                      }
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "Unknown status filter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Unknown status \"foo\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/emails/batch": {
      "post": {
        "operationId": "sendEmailBatch",
        "tags": [
          "Emails"
        ],
        "summary": "Send a batch of emails",
        "description": "Up to 100 DISTINCT emails in one call — each with its own recipient, template and props. One round-trip instead of 100.\n\nThis is not a bulk-campaign endpoint: every entry is still a single-recipient message and goes through the same idempotency, suppression, cap and sender checks a single send does. Nothing is skipped for speed.\n\n**Entries succeed and fail independently.** The response is always `202` with a per-index result array in request order — `data[i]` corresponds to `emails[i]`. A success carries `id` and `status`; a failure carries an `error` object with the same codes a single send returns. Check the array, not the status code.\n\nIdempotency: give each entry its own `idempotency_key`, or pass an `Idempotency-Key` header and each entry derives `<header>:<index>`. Retrying a partially-succeeded batch then replays the successes and retries only the failures.\n\nRequires a `write`-scope key.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Namespaces the batch. Each entry derives `<key>:<index>` unless it sets its own `idempotency_key`.",
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "example": "order-confirmations-2026-08-10"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "emails": {
                    "minItems": 1,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "to": {
                          "type": "string",
                          "format": "email",
                          "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                        },
                        "cc": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "email",
                              "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                            },
                            {
                              "minItems": 1,
                              "maxItems": 50,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "format": "email",
                                "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                              }
                            }
                          ]
                        },
                        "bcc": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "email",
                              "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                            },
                            {
                              "minItems": 1,
                              "maxItems": 50,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "format": "email",
                                "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                              }
                            }
                          ]
                        },
                        "template": {
                          "type": "string",
                          "minLength": 1
                        },
                        "props": {
                          "type": "object",
                          "propertyNames": {
                            "type": "string"
                          },
                          "additionalProperties": {}
                        },
                        "locale": {
                          "type": "string",
                          "minLength": 2,
                          "maxLength": 35
                        },
                        "from": {
                          "type": "string",
                          "minLength": 3,
                          "maxLength": 320
                        },
                        "reply_to": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "email",
                              "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                            },
                            {
                              "minItems": 1,
                              "maxItems": 50,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "format": "email",
                                "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                              }
                            }
                          ]
                        },
                        "headers": {
                          "type": "object",
                          "propertyNames": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 128
                          },
                          "additionalProperties": {
                            "type": "string",
                            "maxLength": 998
                          }
                        },
                        "tags": {
                          "maxItems": 10,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 256
                              },
                              "value": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 256
                              }
                            },
                            "required": [
                              "name",
                              "value"
                            ]
                          }
                        },
                        "scheduled_at": {
                          "type": "string",
                          "minLength": 1
                        },
                        "attachments": {
                          "maxItems": 10,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "filename": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 255
                              },
                              "content": {
                                "type": "string",
                                "minLength": 1
                              },
                              "content_type": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "filename",
                              "content"
                            ]
                          }
                        },
                        "idempotency_key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 256
                        }
                      },
                      "required": [
                        "to",
                        "template"
                      ]
                    },
                    "description": "Up to 100 distinct messages, each with its own recipient and template. Results come back in this order."
                  }
                },
                "required": [
                  "emails"
                ]
              },
              "example": {
                "emails": [
                  {
                    "to": "jane@acme.com",
                    "template": "receipt",
                    "props": {
                      "total": "£42.00"
                    }
                  },
                  {
                    "to": "sam@acme.com",
                    "template": "welcome",
                    "props": {
                      "firstName": "Sam"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. Every entry has a result; read `data` for per-entry outcomes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "description": "Same order as the request.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "index": {
                            "type": "integer",
                            "examples": [
                              0
                            ]
                          },
                          "id": {
                            "type": "string",
                            "examples": [
                              "msg_3aF9c1"
                            ]
                          },
                          "status": {
                            "type": "string",
                            "examples": [
                              "queued"
                            ]
                          },
                          "deduplicated": {
                            "type": "boolean",
                            "description": "An idempotency key matched a prior send."
                          },
                          "error": {
                            "type": "object",
                            "description": "Present instead of `id`/`status` when this entry failed.",
                            "properties": {
                              "code": {
                                "type": "string"
                              },
                              "message": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    },
                    "queued": {
                      "type": "integer",
                      "examples": [
                        2
                      ]
                    },
                    "failed": {
                      "type": "integer",
                      "examples": [
                        0
                      ]
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "index": 0,
                      "id": "msg_3aF9c1",
                      "status": "queued"
                    },
                    {
                      "index": 1,
                      "error": {
                        "code": "template_not_found",
                        "message": "No template 'welcom'."
                      }
                    }
                  ],
                  "queued": 1,
                  "failed": 1
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key's authorization is short on one of two axes: it is below `write`, or it lacks the approval grant. The grant is a separate boolean, not a rung above `write` — a key can hold `admin` and still be refused here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires the send grant (deliver mail to a real inbox) — this key does not have it.",
                    "required_grant": "approve",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "x-requires-approval": true
      }
    },
    "/api/v1/emails/{id}": {
      "get": {
        "operationId": "getMessage",
        "tags": [
          "Emails"
        ],
        "summary": "Get message status",
        "description": "Returns a message's current status and its provider event timeline. Requires a `write`-scope key.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Message id returned by a send.",
            "schema": {
              "type": "string"
            },
            "example": "msg_3aF9c1"
          }
        ],
        "responses": {
          "200": {
            "description": "The message and its events.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageStatus"
                },
                "example": {
                  "id": "msg_3aF9c1",
                  "to": "jane@acme.com",
                  "from": "hello@acme.com",
                  "subject": "Welcome to Acme",
                  "template": "welcome",
                  "status": "delivered",
                  "source": "api",
                  "error": null,
                  "suppressed_reason": null,
                  "provider": "resend",
                  "provider_message_id": "re_abc123",
                  "ab_variant": null,
                  "scheduled_at": null,
                  "sent_at": "2026-07-20T14:31:02Z",
                  "created_at": "2026-07-20T14:31:01Z",
                  "events": [
                    {
                      "type": "sent",
                      "provider": "resend",
                      "occurred_at": "2026-07-20T14:31:02Z"
                    },
                    {
                      "type": "delivered",
                      "provider": "resend",
                      "occurred_at": "2026-07-20T14:31:05Z"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No such message in this project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such message in this project."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "rescheduleEmail",
        "tags": [
          "Emails"
        ],
        "summary": "Reschedule an email",
        "description": "Moves a still-`scheduled` send to a new time (ISO 8601 or natural language). Fails once the message has left the scheduled state.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Message id of a scheduled send.",
            "schema": {
              "type": "string"
            },
            "example": "msg_3aF9c1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "scheduled_at": {
                    "type": "string",
                    "minLength": 1,
                    "description": "New time — ISO 8601 or natural language.",
                    "examples": [
                      "in 3 hours"
                    ]
                  }
                },
                "required": [
                  "scheduled_at"
                ]
              },
              "example": {
                "scheduled_at": "2026-08-02T09:00:00Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rescheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "scheduled"
                      ]
                    },
                    "scheduled_at": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "id": "msg_3aF9c1",
                  "status": "scheduled",
                  "scheduled_at": "2026-08-02T09:00:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "400": {
            "description": "Invalid time, or the message isn't scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Message is \"sent\", not scheduled — cannot reschedule."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "401": {
            "description": "Missing or invalid key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Provide a valid API key."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key's authorization is short on one of two axes: it is below `write`, or it lacks the approval grant. The grant is a separate boolean, not a rung above `write` — a key can hold `admin` and still be refused here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires the send grant (deliver mail to a real inbox) — this key does not have it.",
                    "required_grant": "approve",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No such message in this project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such message in this project."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "x-requires-approval": true
      },
      "delete": {
        "operationId": "cancelEmail",
        "tags": [
          "Emails"
        ],
        "summary": "Cancel an email",
        "description": "Cancels a still-`scheduled` send before it goes out and drops its worker job. Fails once the message has left the scheduled state.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Message id of a scheduled send.",
            "schema": {
              "type": "string"
            },
            "example": "msg_3aF9c1"
          }
        ],
        "responses": {
          "200": {
            "description": "Canceled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "canceled"
                      ]
                    }
                  }
                },
                "example": {
                  "id": "msg_3aF9c1",
                  "status": "canceled"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "400": {
            "description": "The message isn't in a scheduled state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Message is \"sent\", not scheduled — cannot cancel."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "401": {
            "description": "Missing or invalid key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Provide a valid API key."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No such message in this project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such message in this project."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/contacts": {
      "post": {
        "operationId": "upsertContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Upsert a contact",
        "description": "Creates or updates a contact by email. `attributes` are shallow-merged onto any existing attributes.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "description": "Contact's email address (the identity key).",
                    "examples": [
                      "jane@acme.com"
                    ]
                  },
                  "external_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "Your own stable id for this contact.",
                    "examples": [
                      "user_8f21"
                    ]
                  },
                  "attributes": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "Custom attributes. Shallow-merged onto any existing attributes.",
                    "examples": [
                      {
                        "plan": "Pro",
                        "firstName": "Jane",
                        "timezone": "America/New_York"
                      }
                    ]
                  },
                  "tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 60
                    },
                    "description": "Label set for the contact (replaces the existing set when provided). Segments/automations match tags with the `contains` operator on `contact.tags`.",
                    "examples": [
                      [
                        "vip",
                        "beta"
                      ]
                    ]
                  }
                },
                "required": [
                  "email"
                ]
              },
              "example": {
                "email": "jane@acme.com",
                "external_id": "user_8f21",
                "attributes": {
                  "plan": "Pro",
                  "firstName": "Jane"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing contact updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactResult"
                },
                "example": {
                  "id": "ct_7Kd2",
                  "created": false
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "201": {
            "description": "New contact created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactResult"
                },
                "example": {
                  "id": "ct_7Kd2",
                  "created": true
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "get": {
        "operationId": "listContacts",
        "tags": [
          "Contacts"
        ],
        "summary": "List contacts",
        "description": "Lists contacts newest-first. Filter by `tag`; page with `limit` + `before`. Requires a `write`-scope key.",
        "parameters": [
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "description": "Only contacts carrying this tag.",
            "schema": {
              "type": "string"
            },
            "example": "vip"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size (1–100, default 50).",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "Deprecated — use `cursor`. ISO 8601 `created_at`: rows older than this.",
            "schema": {
              "type": "string"
            },
            "deprecated": true,
            "x-sunset": "2027-04-05T00:00:00.000Z",
            "x-deprecation-link": "https://sendandretain.com/docs/api/pagination",
            "x-replaced-by": "?cursor="
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of contacts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/contacts/{id}": {
      "get": {
        "operationId": "getContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Get a contact",
        "description": "Returns a contact with its attributes, tags, and subscription state. Requires a `write`-scope key.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Contact id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The contact.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No such contact in this project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such contact in this project."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "delete": {
        "operationId": "deleteContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Delete a contact",
        "description": "Hard-deletes a contact and its events; sent-message history is retained for the audit log. Requires a `write`-scope key.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Contact id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "deleted": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No such contact in this project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such contact in this project."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/suppressions": {
      "get": {
        "operationId": "listSuppressions",
        "tags": [
          "Suppressions"
        ],
        "summary": "List suppressions",
        "description": "Lists suppressed addresses (the do-not-send list). Filter by `reason`. Requires a `write`-scope key.",
        "parameters": [
          {
            "name": "reason",
            "in": "query",
            "required": false,
            "description": "unsubscribe | invalid | bounce | complaint | manual.",
            "schema": {
              "type": "string",
              "enum": [
                "unsubscribe",
                "invalid",
                "bounce",
                "complaint",
                "manual"
              ]
            },
            "example": "bounce"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size (1–500, default 100).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Suppressed addresses.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "post": {
        "operationId": "addSuppression",
        "tags": [
          "Suppressions"
        ],
        "summary": "Add a suppression",
        "description": "Adds an address to the do-not-send list. Requires a `write`-scope key.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "Address to suppress."
                  },
                  "reason": {
                    "type": "string",
                    "enum": [
                      "unsubscribe",
                      "bounce",
                      "complaint",
                      "manual"
                    ],
                    "description": "Defaults to `manual`. `invalid` is not settable here — it's written only by address verification, like `bounce`/`complaint` are written only by provider webhooks."
                  },
                  "note": {
                    "type": "string",
                    "description": "Free-text note."
                  }
                }
              },
              "example": {
                "email": "bounced@acme.com",
                "reason": "manual",
                "note": "hard bounce from import"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Suppressed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "email": {
                      "type": "string"
                    },
                    "suppressed": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "Invalid email or reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "A valid email is required."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict — the key was used with a different body, or the first request with it is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This Idempotency-Key was already used with a different request body. Use a new key for a different request."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      },
      "delete": {
        "operationId": "removeSuppression",
        "tags": [
          "Suppressions"
        ],
        "summary": "Remove a suppression",
        "description": "Removes an address from the do-not-send list. Complaint suppressions are permanent and cannot be removed. Requires a `write`-scope key.",
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": true,
            "description": "Address to un-suppress.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "email": {
                      "type": "string"
                    },
                    "removed": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "Missing email, or the suppression is permanent (complaint).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Complaint suppressions can't be removed."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/events": {
      "post": {
        "operationId": "emitEvent",
        "tags": [
          "Events"
        ],
        "summary": "Emit a contact event",
        "description": "Records an event for a contact (creating the contact if you pass an unknown email). Provide `email` or `external_id`.\n\nAccepted and queued: you get `202` with an id the moment the event is durably stored, and the contact upsert plus automation enrollment run in the background. This endpoint is designed to be called from inside your own user-facing request, so it never makes you wait on that work — the same reason `202 Accepted` is the only answer SendGrid's send endpoint gives.\n\nTo see what an event actually did — which automations enrolled and why the others declined — read the contact's timeline with `GET /api/v1/contacts/{id}/events`; each event carries its recorded outcome.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "description": "Identifies the contact; creates it if unknown. Provide this or external_id.",
                    "examples": [
                      "jane@acme.com"
                    ]
                  },
                  "external_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "Identifies an existing contact by your id. Provide this or email.",
                    "examples": [
                      "user_8f21"
                    ]
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "pattern": "^[a-zA-Z0-9_.:-]+$",
                    "description": "Event name. Letters, digits, and `_ . : -`.",
                    "examples": [
                      "order.completed"
                    ]
                  },
                  "properties": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "Event properties — available to automation trigger filters.",
                    "examples": [
                      {
                        "orderId": "ord_991",
                        "total": 42.5
                      }
                    ]
                  },
                  "dedupe_key": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "Idempotency key for this event. A repeat is a no-op for 30 days — the retention window on the event log. Past that the event row is pruned and its key becomes free again, so a replay of a genuinely old event is accepted as new. Automations are unaffected either way: enrolment is guarded by the run history, which is never pruned.",
                    "examples": [
                      "ord_991"
                    ]
                  },
                  "occurred_at": {
                    "type": "string",
                    "format": "date-time",
                    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                    "description": "ISO 8601 timestamp (with offset) of when the event happened.",
                    "examples": [
                      "2026-07-20T14:30:00Z"
                    ]
                  },
                  "contact_attributes": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "Attributes to upsert onto the contact alongside the event.",
                    "examples": [
                      {
                        "lastOrderAt": "2026-07-20"
                      }
                    ]
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "email": "jane@acme.com",
                "name": "order.completed",
                "properties": {
                  "orderId": "ord_991",
                  "total": 42.5
                },
                "dedupe_key": "ord_991"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. The event is durably stored and will be processed in the background. A repeated `dedupe_key` is accepted the same way and collapses when processed, so a retry after a timeout is always safe.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "status"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "Queued event id."
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "queued"
                      ]
                    }
                  }
                },
                "example": {
                  "id": "9f1c2e77-5a1e-4a1a-9c66-1f0f3f4b2d10",
                  "status": "queued"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/templates": {
      "post": {
        "operationId": "createTemplate",
        "tags": [
          "Templates"
        ],
        "summary": "Create a template",
        "description": "Creates a template and its first draft version. Drafts cannot send — render it, test it, then publish. Requires a `write`-scope key.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "slug": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 60,
                    "pattern": "^[a-z0-9][a-z0-9-]*$",
                    "description": "kebab-case identity, unique in the project. This is what `POST /api/v1/emails` sends by.",
                    "examples": [
                      "welcome"
                    ]
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "description": "Human label for the dashboard.",
                    "examples": [
                      "Welcome email"
                    ]
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "transactional",
                      "lifecycle"
                    ],
                    "description": "`transactional` (receipts, resets — delivered even to unsubscribed contacts) or `lifecycle` (marketing email — not delivered to unsubscribed contacts). Both carry List-Unsubscribe headers and an unsubscribe footer; the category decides only who an existing unsubscribe blocks.",
                    "examples": [
                      "transactional"
                    ]
                  },
                  "subject": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "Subject line. Supports `{{variable}}` interpolation.",
                    "examples": [
                      "Welcome to Acme, {{firstName}}"
                    ]
                  },
                  "tsx_source": {
                    "type": "string",
                    "minLength": 20,
                    "maxLength": 100000,
                    "description": "react.email TSX. May import only `react` and `@react-email/components` — the allowlist is enforced at compile time and a violation returns `invalid_request`."
                  },
                  "variables": {
                    "default": [],
                    "maxItems": 40,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 60
                        },
                        "type": {
                          "default": "string",
                          "type": "string",
                          "enum": [
                            "string",
                            "number",
                            "boolean",
                            "object",
                            "array"
                          ]
                        },
                        "required": {
                          "type": "boolean"
                        },
                        "example": {},
                        "fallback": {}
                      },
                      "required": [
                        "name"
                      ]
                    },
                    "description": "Declared template variables, used to generate example props for rendering."
                  }
                },
                "required": [
                  "slug",
                  "name",
                  "category",
                  "subject",
                  "tsx_source"
                ]
              },
              "example": {
                "slug": "welcome",
                "name": "Welcome email",
                "category": "transactional",
                "subject": "Welcome to Acme, {{firstName}}",
                "tsx_source": "import { Html, Head, Preview, Body, Text } from '@react-email/components';\nexport default function Welcome({ firstName }) {\n  return (<Html><Head /><Preview>{`Welcome, ${firstName}`}</Preview><Body><Text>Hi {firstName}</Text></Body></Html>);\n}",
                "variables": [
                  {
                    "name": "firstName",
                    "type": "string",
                    "required": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Template created as an unpublished draft.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "slug": {
                      "type": "string"
                    },
                    "version": {
                      "type": "integer",
                      "examples": [
                        1
                      ]
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "draft"
                      ]
                    }
                  }
                },
                "example": {
                  "id": "tpl_9Xa2",
                  "slug": "welcome",
                  "version": 1,
                  "status": "draft"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict — the key was used with a different body, or the first request with it is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This Idempotency-Key was already used with a different request body. Use a new key for a different request."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      },
      "get": {
        "operationId": "listTemplates",
        "tags": [
          "Templates"
        ],
        "summary": "List templates",
        "description": "Every non-archived template in the project, most recently updated first.",
        "responses": {
          "200": {
            "description": "Templates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "slug": {
                            "type": "string",
                            "examples": [
                              "welcome"
                            ]
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "category": {
                            "type": "string",
                            "examples": [
                              "transactional"
                            ]
                          },
                          "sender_id": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "published": {
                            "type": "boolean",
                            "description": "True when a version is live and sendable."
                          },
                          "updated_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/templates/{slug}": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "Template slug.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getTemplate",
        "tags": [
          "Templates"
        ],
        "summary": "Get a template",
        "description": "Full TSX source, subject and variables for one version (default: the latest).",
        "parameters": [
          {
            "name": "version",
            "in": "query",
            "required": false,
            "description": "Version number. Omit for the latest.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Template version.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "slug": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "category": {
                      "type": "string"
                    },
                    "sender_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "published": {
                      "type": "boolean"
                    },
                    "version": {
                      "type": "integer",
                      "examples": [
                        2
                      ]
                    },
                    "version_status": {
                      "type": "string",
                      "examples": [
                        "published"
                      ]
                    },
                    "is_current": {
                      "type": "boolean",
                      "description": "True when this is the version that sends."
                    },
                    "subject": {
                      "type": "string"
                    },
                    "tsx_source": {
                      "type": "string"
                    },
                    "variables": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "updateTemplate",
        "tags": [
          "Templates"
        ],
        "summary": "Edit a template",
        "description": "Published versions are immutable, so this always creates a NEW draft version, carrying over any field you omit. Publish it separately — an edit never changes what is currently sending.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "subject": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "New subject line.",
                    "examples": [
                      "Welcome aboard, {{firstName}}"
                    ]
                  },
                  "tsx_source": {
                    "type": "string",
                    "minLength": 20,
                    "maxLength": 100000,
                    "description": "New TSX source. Omit to carry the current source forward."
                  },
                  "variables": {
                    "maxItems": 40,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 60
                        },
                        "type": {
                          "default": "string",
                          "type": "string",
                          "enum": [
                            "string",
                            "number",
                            "boolean",
                            "object",
                            "array"
                          ]
                        },
                        "required": {
                          "type": "boolean"
                        },
                        "example": {},
                        "fallback": {}
                      },
                      "required": [
                        "name"
                      ]
                    }
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "transactional",
                      "lifecycle"
                    ]
                  },
                  "variant_key": {
                    "type": "string",
                    "maxLength": 20,
                    "description": "Create this draft as an A/B variant instead of the base mainline.",
                    "examples": [
                      "b"
                    ]
                  }
                }
              },
              "example": {
                "subject": "Welcome aboard, {{firstName}}"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New draft version created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "version": {
                      "type": "integer",
                      "examples": [
                        2
                      ]
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "draft"
                      ]
                    }
                  }
                },
                "example": {
                  "slug": "welcome",
                  "version": 2,
                  "status": "draft"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "delete": {
        "operationId": "archiveTemplate",
        "tags": [
          "Templates"
        ],
        "summary": "Archive a template",
        "description": "Archives the template. Refused while an ACTIVE automation still sends it, so a live automation can't be broken from the API.",
        "responses": {
          "200": {
            "description": "Template archived.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "archived": {
                      "type": "boolean"
                    }
                  }
                },
                "example": {
                  "slug": "welcome",
                  "archived": true
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "Still in use by an active automation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Still used by active automation \"Win back\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/templates/{slug}/meta": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "Template slug.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "patch": {
        "operationId": "updateTemplateMeta",
        "tags": [
          "Templates"
        ],
        "summary": "Edit subject, preview text, or sender",
        "description": "The \"just fix the email meta\" path — no new TSX. Subject and preview-text edits are copy-on-write (a new draft version) and are **auto-published when the template is already published**, so the change actually sends instead of stranding a draft. The sender updates in place.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "subject": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "New subject line.",
                    "examples": [
                      "Your Acme receipt"
                    ]
                  },
                  "preview_text": {
                    "type": "string",
                    "maxLength": 300,
                    "description": "Inbox preview text (the preheader). Rewrites the template's `<Preview>` line. Pass `\"\"` to clear it.",
                    "examples": [
                      "Order #991 — thanks for your purchase"
                    ]
                  },
                  "sender_id": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Sender identity for this template. `null` resets to the project default sender.",
                    "examples": [
                      "snd_2Kp8"
                    ]
                  }
                }
              },
              "example": {
                "subject": "Your Acme receipt",
                "preview_text": "Order #991 — thanks!"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Meta updated. `version` is the new version number, or null when only the sender changed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "version": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    }
                  }
                },
                "example": {
                  "slug": "welcome",
                  "version": 3
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/templates/{slug}/versions": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "Template slug.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listTemplateVersions",
        "tags": [
          "Templates"
        ],
        "summary": "List versions",
        "description": "Every version of the template, newest first, including A/B variants and translations.",
        "responses": {
          "200": {
            "description": "Versions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "version": {
                            "type": "integer",
                            "examples": [
                              2
                            ]
                          },
                          "status": {
                            "type": "string",
                            "examples": [
                              "published"
                            ]
                          },
                          "subject": {
                            "type": "string"
                          },
                          "variant_key": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "locale": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "is_current": {
                            "type": "boolean"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "post": {
        "operationId": "publishTemplateVersion",
        "tags": [
          "Templates"
        ],
        "summary": "Publish a version",
        "description": "Flips a draft to published. A published version's content never changes; only its status does. Publishing the base mainline makes it the version that sends; A/B variants and locale translations publish without displacing it (`live: false`).",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "version": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "Version number to publish. Omit to publish the latest draft.",
                    "examples": [
                      2
                    ]
                  }
                }
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Version published.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "version": {
                      "type": "integer",
                      "examples": [
                        2
                      ]
                    },
                    "variant_key": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "live": {
                      "type": "boolean",
                      "description": "True when this version is now what sends."
                    }
                  }
                },
                "example": {
                  "slug": "welcome",
                  "version": 2,
                  "variant_key": null,
                  "live": true
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "delete": {
        "operationId": "unpublishTemplate",
        "tags": [
          "Templates"
        ],
        "summary": "Unpublish a template",
        "description": "Takes a published template back out of service: clears its live version and flips that version back to draft. Every send then refuses with `template_not_published` until you publish again — use this when a template went live before it was ready. Republishing restores it; nothing is archived and no content is lost. Refused while an ACTIVE automation still sends this template — pause those automations first.",
        "responses": {
          "200": {
            "description": "Template unpublished.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "live": {
                      "type": "boolean",
                      "description": "Always false — the template no longer has a live version."
                    }
                  }
                },
                "example": {
                  "slug": "welcome",
                  "live": false
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/templates/{slug}/render": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "Template slug.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "renderTemplate",
        "tags": [
          "Templates"
        ],
        "summary": "Render a template",
        "description": "Compiles and renders a version and returns the HTML, plain text and subject. No side effects — nothing is sent. This is the authoring inner loop: compile and render failures come back as `invalid_request` carrying the verbatim diagnostics, so you can fix the source and retry.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "version": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "Version to render. Omit for the latest.",
                    "examples": [
                      2
                    ]
                  },
                  "props": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "Values for the template's variables. Omit to render with generated example props.",
                    "examples": [
                      {
                        "firstName": "Jane"
                      }
                    ]
                  }
                }
              },
              "example": {
                "props": {
                  "firstName": "Jane"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rendered output.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "version": {
                      "type": "integer",
                      "examples": [
                        2
                      ]
                    },
                    "subject": {
                      "type": "string",
                      "examples": [
                        "Welcome to Acme, Jane"
                      ]
                    },
                    "html": {
                      "type": "string"
                    },
                    "text": {
                      "type": "string"
                    },
                    "props_used": {
                      "type": "object",
                      "description": "The props actually rendered with — generated examples when you passed none."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The template failed to compile or render. The message is the raw diagnostics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Line 4: 'lodash' is not an allowed import."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/templates/{slug}/test": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "Template slug.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "sendTemplateTest",
        "tags": [
          "Templates"
        ],
        "summary": "Send a test email",
        "description": "Sends a `[TEST]`-prefixed copy to one inbox. Works on an unpublished draft — that's the point, you test before you publish. Test sends deliberately skip idempotency, suppression and the daily cap, but every attempt is still logged.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "to": {
                    "type": "string",
                    "format": "email",
                    "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "description": "Where to send the test.",
                    "examples": [
                      "you@yourcompany.com"
                    ]
                  },
                  "version": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "Version to send. Omit for the latest — drafts included.",
                    "examples": [
                      2
                    ]
                  },
                  "props": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "Values for the template's variables.",
                    "examples": [
                      {
                        "firstName": "Jane"
                      }
                    ]
                  }
                },
                "required": [
                  "to"
                ]
              },
              "example": {
                "to": "you@yourcompany.com",
                "props": {
                  "firstName": "Jane"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Test sent.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "to": {
                      "type": "string"
                    },
                    "subject": {
                      "type": "string",
                      "examples": [
                        "[TEST] Welcome to Acme, Jane"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key's authorization is short on one of two axes: it is below `write`, or it lacks the approval grant. The grant is a separate boolean, not a rung above `write` — a key can hold `admin` and still be refused here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires the send grant (deliver mail to a real inbox) — this key does not have it.",
                    "required_grant": "approve",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "x-requires-approval": true
      }
    },
    "/api/v1/templates/{slug}/translations": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "Template slug.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "addTemplateTranslation",
        "tags": [
          "Templates"
        ],
        "summary": "Add a translation",
        "description": "Creates a locale-tagged version. Publish it like any other version; the send path picks it when a request passes a matching `locale` and falls back to the base language otherwise.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "locale": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 35,
                    "pattern": "^[a-z]{2,3}(-[A-Za-z0-9]{2,8})?$",
                    "description": "BCP-47-ish locale tag.",
                    "examples": [
                      "fr"
                    ]
                  },
                  "subject": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "Translated subject line.",
                    "examples": [
                      "Bienvenue chez Acme"
                    ]
                  },
                  "tsx_source": {
                    "type": "string",
                    "minLength": 20,
                    "maxLength": 100000,
                    "description": "Translated TSX. Omit to translate the subject only and reuse the base layout."
                  }
                },
                "required": [
                  "locale",
                  "subject"
                ]
              },
              "example": {
                "locale": "fr",
                "subject": "Bienvenue chez Acme, {{firstName}}"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Translation draft created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "locale": {
                      "type": "string",
                      "examples": [
                        "fr"
                      ]
                    },
                    "version": {
                      "type": "integer",
                      "examples": [
                        3
                      ]
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "draft"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No template matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No template \"welcome\"."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations": {
      "post": {
        "operationId": "createAutomation",
        "tags": [
          "Automations"
        ],
        "summary": "Create an automation",
        "description": "Creates a trigger-driven automation, optionally with its steps. **Always created paused** — enabling is a separate, deliberate call (`POST /api/v1/automations/{id}/status`) so a programmatic mistake can never start sending. Step objects are camelCase (they reuse the internal step schema); the surrounding body is snake_case like the rest of the API.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120,
                    "description": "Display name, unique within the project.",
                    "examples": [
                      "Win back"
                    ]
                  },
                  "trigger_event": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "description": "Contact event that enrolls a contact.",
                    "examples": [
                      "subscription.canceled"
                    ]
                  },
                  "trigger_filter": {
                    "anyOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "path": {
                              "type": "string",
                              "minLength": 1,
                              "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                            },
                            "op": {
                              "default": "eq",
                              "type": "string",
                              "enum": [
                                "eq",
                                "neq",
                                "exists",
                                "not_exists",
                                "in",
                                "gt",
                                "lt",
                                "contains",
                                "within_days",
                                "older_than_days"
                              ]
                            },
                            "value": {}
                          },
                          "required": [
                            "path"
                          ]
                        }
                      },
                      {
                        "$ref": "#/components/schemas/CreateAutomation___schema0"
                      }
                    ],
                    "description": "Conditions over contact attributes ⊕ event properties. All must match to enroll.",
                    "examples": [
                      [
                        {
                          "field": "contact.attributes.plan",
                          "operator": "equals",
                          "value": "Pro"
                        }
                      ]
                    ]
                  },
                  "priority": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 1000,
                    "description": "Lower runs first when several automations match. Default 100.",
                    "examples": [
                      100
                    ]
                  },
                  "exclusive": {
                    "type": "boolean",
                    "description": "When true (default), a contact already in this automation is not re-enrolled."
                  },
                  "exit_events": {
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 120
                    },
                    "description": "Events that end an in-flight run early, ORed.",
                    "examples": [
                      [
                        "subscription.resumed"
                      ]
                    ]
                  },
                  "exit_event": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Deprecated single-event form, still accepted. Prefer `exit_events`.",
                    "examples": [
                      "subscription.resumed"
                    ]
                  },
                  "allow_reenrollment": {
                    "type": "boolean",
                    "description": "Allow a contact to enroll again after finishing."
                  },
                  "reenrollment_cooldown_seconds": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 9007199254740991
                  },
                  "steps": {
                    "maxItems": 200,
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/CreateAutomation___schema1"
                    },
                    "description": "Steps in order. Omit to create an empty shell and append later."
                  }
                },
                "required": [
                  "name",
                  "trigger_event"
                ]
              },
              "example": {
                "name": "Win back",
                "trigger_event": "subscription.canceled",
                "steps": [
                  {
                    "type": "send",
                    "templateSlug": "win-back-1",
                    "delaySeconds": 0
                  },
                  {
                    "type": "delay",
                    "delaySeconds": 259200
                  },
                  {
                    "type": "send",
                    "templateSlug": "win-back-2",
                    "delaySeconds": 0,
                    "subject": "One last thing"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Automation created, paused.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "automation_id": {
                      "type": "string"
                    },
                    "step_count": {
                      "type": "integer"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "paused"
                      ]
                    }
                  }
                },
                "example": {
                  "automation_id": "auto_win_back",
                  "step_count": 3,
                  "status": "paused"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict — the key was used with a different body, or the first request with it is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This Idempotency-Key was already used with a different request body. Use a new key for a different request."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      },
      "get": {
        "operationId": "listAutomations",
        "tags": [
          "Automations"
        ],
        "summary": "List automations",
        "description": "Every non-archived automation in the project, lowest `priority` first.",
        "responses": {
          "200": {
            "description": "Automations.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string",
                            "examples": [
                              "paused"
                            ]
                          },
                          "trigger_event": {
                            "type": "string"
                          },
                          "priority": {
                            "type": "integer"
                          },
                          "step_count": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "auto_win_back",
                      "name": "Win back",
                      "status": "paused",
                      "trigger_event": "subscription.canceled",
                      "priority": 100,
                      "step_count": 3
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations/steps": {
      "post": {
        "operationId": "addAutomationSteps",
        "tags": [
          "Automations"
        ],
        "summary": "Append automation steps",
        "description": "Appends steps to an automation or a branch lane. Appending to a live automation is safe — in-flight contacts advance by stable step id, so they are never disturbed. Use `after_position` to insert, or `parent_step_id` + `lane_key` to target a branch lane.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "automation": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Automation id or name.",
                    "examples": [
                      "Win back"
                    ]
                  },
                  "steps": {
                    "minItems": 1,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/AddAutomationSteps___schema0"
                    },
                    "description": "Steps to append, in order."
                  },
                  "after_position": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991,
                    "description": "Insert after this position instead of appending. Requires a paused automation.",
                    "examples": [
                      2
                    ]
                  },
                  "parent_step_id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Append into a branch lane owned by this step.",
                    "examples": [
                      "step_7Qa1"
                    ]
                  },
                  "lane_key": {
                    "type": "string",
                    "description": "Which lane of the parent branch — e.g. `yes` / `no`, or a multi-branch key.",
                    "examples": [
                      "yes"
                    ]
                  }
                },
                "required": [
                  "automation",
                  "steps"
                ]
              },
              "example": {
                "automation": "Win back",
                "steps": [
                  {
                    "type": "send",
                    "templateSlug": "win-back-3",
                    "delaySeconds": 0
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Steps appended.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "added": {
                      "type": "integer"
                    },
                    "total_steps": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "added": 1,
                  "total_steps": 4
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "syncAutomationStepProps",
        "tags": [
          "Automations"
        ],
        "summary": "Bulk-set step props",
        "description": "Refreshes `props_overrides` across send steps by position — the content-pipeline path for a recurring automation whose copy changes per edition. `merge: true` shallow-merges into the existing overrides instead of replacing them.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "automation": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Automation id or name.",
                    "examples": [
                      "Weekly digest"
                    ]
                  },
                  "updates": {
                    "minItems": 1,
                    "maxItems": 200,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "position": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "props_overrides": {
                          "type": "object",
                          "propertyNames": {
                            "type": "string"
                          },
                          "additionalProperties": {}
                        }
                      },
                      "required": [
                        "position",
                        "props_overrides"
                      ]
                    },
                    "description": "One entry per send step, addressed by its global `position`."
                  },
                  "merge": {
                    "type": "boolean",
                    "description": "Shallow-merge into existing overrides instead of replacing them."
                  }
                },
                "required": [
                  "automation",
                  "updates"
                ]
              },
              "example": {
                "automation": "Weekly digest",
                "updates": [
                  {
                    "position": 1,
                    "props_overrides": {
                      "headline": "This week in Acme"
                    }
                  }
                ],
                "merge": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Steps updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "updated": {
                      "type": "integer"
                    },
                    "positions": {
                      "type": "array",
                      "items": {
                        "type": "integer"
                      }
                    }
                  }
                },
                "example": {
                  "updated": 1,
                  "positions": [
                    1
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "put": {
        "operationId": "updateAutomationStep",
        "tags": [
          "Automations"
        ],
        "summary": "Edit a step",
        "description": "Edits one step in place, addressed by position. Step TYPE is immutable — to change it, remove the step and add a new one. While the automation is ACTIVE only steps no run has reached yet may be edited; otherwise pause first.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "automation": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Automation id or name.",
                    "examples": [
                      "Win back"
                    ]
                  },
                  "position": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991,
                    "description": "The step's globally-unique position within the automation.",
                    "examples": [
                      2
                    ]
                  },
                  "patch": {
                    "type": "object",
                    "properties": {
                      "templateSlug": {
                        "type": "string"
                      },
                      "propsOverrides": {
                        "type": "object",
                        "propertyNames": {
                          "type": "string"
                        },
                        "additionalProperties": {}
                      },
                      "subject": {
                        "description": "Send steps: per-step subject override ({{vars}} ok); null clears.",
                        "anyOf": [
                          {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 300
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "previewText": {
                        "description": "Send steps: per-step inbox preview text ({{vars}} ok); null clears.",
                        "anyOf": [
                          {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 300
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "eventName": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 120
                      },
                      "timeoutSeconds": {
                        "type": "integer",
                        "minimum": 60,
                        "maximum": 7776000
                      },
                      "filter": {
                        "anyOf": [
                          {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "path": {
                                  "type": "string",
                                  "minLength": 1,
                                  "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                                },
                                "op": {
                                  "default": "eq",
                                  "type": "string",
                                  "enum": [
                                    "eq",
                                    "neq",
                                    "exists",
                                    "not_exists",
                                    "in",
                                    "gt",
                                    "lt",
                                    "contains",
                                    "within_days",
                                    "older_than_days"
                                  ]
                                },
                                "value": {}
                              },
                              "required": [
                                "path"
                              ]
                            }
                          },
                          {
                            "$ref": "#/components/schemas/UpdateStep___schema0"
                          }
                        ]
                      },
                      "ifMatch": {
                        "type": "string",
                        "enum": [
                          "continue",
                          "exit"
                        ]
                      },
                      "ifNoMatch": {
                        "type": "string",
                        "enum": [
                          "continue",
                          "exit"
                        ]
                      },
                      "branches": {
                        "description": "Multi branch only: replace the ordered arms (first match wins).",
                        "minItems": 1,
                        "maxItems": 8,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "key": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 40
                            },
                            "label": {
                              "type": "string",
                              "maxLength": 60
                            },
                            "filter": {
                              "anyOf": [
                                {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "path": {
                                        "type": "string",
                                        "minLength": 1,
                                        "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                                      },
                                      "op": {
                                        "default": "eq",
                                        "type": "string",
                                        "enum": [
                                          "eq",
                                          "neq",
                                          "exists",
                                          "not_exists",
                                          "in",
                                          "gt",
                                          "lt",
                                          "contains",
                                          "within_days",
                                          "older_than_days"
                                        ]
                                      },
                                      "value": {}
                                    },
                                    "required": [
                                      "path"
                                    ]
                                  }
                                },
                                {
                                  "$ref": "#/components/schemas/UpdateStep___schema0"
                                }
                              ]
                            }
                          },
                          "required": [
                            "key",
                            "filter"
                          ]
                        }
                      },
                      "convertKind": {
                        "type": "string",
                        "const": "yes_no"
                      },
                      "label": {
                        "description": "Exit steps: the label shown in metrics.",
                        "type": "string",
                        "maxLength": 60
                      },
                      "attributes": {
                        "type": "object",
                        "propertyNames": {
                          "type": "string"
                        },
                        "additionalProperties": {}
                      },
                      "addTags": {
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 60
                        }
                      },
                      "removeTags": {
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 60
                        }
                      },
                      "url": {
                        "type": "string",
                        "format": "uri"
                      },
                      "method": {
                        "type": "string",
                        "enum": [
                          "POST",
                          "PUT"
                        ]
                      },
                      "delaySeconds": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9007199254740991
                      },
                      "skipped": {
                        "description": "Debug switch: runs walk past this step without executing it — no send, no webhook, no wait. Editable while the automation is active.",
                        "type": "boolean"
                      },
                      "sendWindow": {
                        "description": "Quiet-hours clamp; contact.attributes.timezone wins over this timezone.",
                        "type": "object",
                        "properties": {
                          "days": {
                            "type": "array",
                            "items": {
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 7
                            }
                          },
                          "startHour": {
                            "type": "integer",
                            "minimum": 0,
                            "maximum": 23
                          },
                          "endHour": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 24
                          },
                          "timezone": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "description": "Fields to change. Keys are validated against the step's actual type."
                  }
                },
                "required": [
                  "automation",
                  "position",
                  "patch"
                ]
              },
              "example": {
                "automation": "Win back",
                "position": 2,
                "patch": {
                  "subject": "One last thing",
                  "previewText": "We saved your spot"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Step updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "position": {
                      "type": "integer",
                      "examples": [
                        2
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation or step matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "delete": {
        "operationId": "removeAutomationStep",
        "tags": [
          "Automations"
        ],
        "summary": "Remove a step",
        "description": "Removes a step by position. Requires a PAUSED automation — deleting a step an in-flight run might still be waiting on would strand it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "automation": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Automation id or name.",
                    "examples": [
                      "Win back"
                    ]
                  },
                  "position": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991,
                    "description": "Step position to remove. Requires a paused automation.",
                    "examples": [
                      3
                    ]
                  }
                },
                "required": [
                  "automation",
                  "position"
                ]
              },
              "example": {
                "automation": "Win back",
                "position": 3
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Step removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "removed_position": {
                      "type": "integer",
                      "examples": [
                        3
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation or step matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations/steps/move": {
      "post": {
        "operationId": "moveAutomationStep",
        "tags": [
          "Automations"
        ],
        "summary": "Reorder a step",
        "description": "Moves a step among its lane siblings — never across into another branch arm. Requires a paused automation.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "automation": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Automation id or name.",
                    "examples": [
                      "Win back"
                    ]
                  },
                  "position": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991,
                    "description": "Step to move.",
                    "examples": [
                      3
                    ]
                  },
                  "direction": {
                    "type": "string",
                    "enum": [
                      "up",
                      "down"
                    ],
                    "description": "Shift one slot among lane siblings.",
                    "examples": [
                      "up"
                    ]
                  },
                  "to_index": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 9007199254740991,
                    "description": "Target index among lane siblings. Wins over `direction`.",
                    "examples": [
                      0
                    ]
                  }
                },
                "required": [
                  "automation",
                  "position"
                ]
              },
              "example": {
                "automation": "Win back",
                "position": 3,
                "direction": "up"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Step moved. `position` is its new global address.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "position": {
                      "type": "integer",
                      "examples": [
                        2
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation or step matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Automation id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getAutomation",
        "tags": [
          "Automations"
        ],
        "summary": "Get an automation",
        "description": "Trigger, filter, settings, and the full ordered step tree.",
        "responses": {
          "200": {
            "description": "Automation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "examples": [
                        "paused"
                      ]
                    },
                    "trigger_event": {
                      "type": "string"
                    },
                    "trigger_filter": {
                      "type": [
                        "array",
                        "object",
                        "null"
                      ]
                    },
                    "priority": {
                      "type": "integer",
                      "examples": [
                        100
                      ]
                    },
                    "exclusive": {
                      "type": "boolean"
                    },
                    "exit_events": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "exit_event": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "allow_reenrollment": {
                      "type": "boolean"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "steps": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "position": {
                            "type": "integer",
                            "examples": [
                              1
                            ]
                          },
                          "parent_step_id": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "lane_key": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "type": {
                            "type": "string",
                            "examples": [
                              "send"
                            ]
                          },
                          "delay_seconds": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "template_slug": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "config": {
                            "type": [
                              "object",
                              "null"
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "updateAutomation",
        "tags": [
          "Automations"
        ],
        "summary": "Edit an automation",
        "description": "Updates the trigger, filter, priority, exit event or name. Trigger and filter changes affect FUTURE enrollments only — contacts mid-run keep advancing through the tree they enrolled into. Steps are edited through the `/steps` endpoints.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "trigger_event": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "description": "New trigger. Affects FUTURE enrollments only.",
                    "examples": [
                      "subscription.canceled"
                    ]
                  },
                  "trigger_filter": {
                    "anyOf": [
                      {
                        "anyOf": [
                          {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "path": {
                                  "type": "string",
                                  "minLength": 1,
                                  "description": "contact.attributes.<key>, contact.engagement.<key>, contact.subscriptionStatus, or event.properties.<key> (bare = event property). Engagement fields: emailsReceived, emailsSinceEngaged, daysSinceEngaged, openCount, clickCount, openRate, clickRate, lastOpenedAt, lastClickedAt."
                                },
                                "op": {
                                  "default": "eq",
                                  "type": "string",
                                  "enum": [
                                    "eq",
                                    "neq",
                                    "exists",
                                    "not_exists",
                                    "in",
                                    "gt",
                                    "lt",
                                    "contains",
                                    "within_days",
                                    "older_than_days"
                                  ]
                                },
                                "value": {}
                              },
                              "required": [
                                "path"
                              ]
                            }
                          },
                          {
                            "$ref": "#/components/schemas/UpdateAutomation___schema0"
                          }
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "New filter, or null to clear it (every occurrence enrolls)."
                  },
                  "priority": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 1000,
                    "description": "Lower runs first when several automations match.",
                    "examples": [
                      50
                    ]
                  },
                  "exclusive": {
                    "type": "boolean"
                  },
                  "exit_events": {
                    "anyOf": [
                      {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 120
                        }
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Events that end an in-flight run early, ORed. Replaces `exit_event`; [] or null clears.",
                    "examples": [
                      [
                        "subscription.resumed"
                      ]
                    ]
                  },
                  "exit_event": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 120
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Deprecated single-event form, still accepted. Prefer `exit_events`. null clears.",
                    "examples": [
                      "subscription.resumed"
                    ]
                  },
                  "allow_reenrollment": {
                    "type": "boolean"
                  },
                  "reenrollment_cooldown_seconds": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 9007199254740991
                  }
                }
              },
              "example": {
                "priority": 50,
                "exit_events": [
                  "subscription.resumed"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Automation updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "delete": {
        "operationId": "archiveAutomation",
        "tags": [
          "Automations"
        ],
        "summary": "Archive an automation",
        "description": "Archives the automation. In-flight runs stop advancing.",
        "responses": {
          "200": {
            "description": "Automation archived.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "archived": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations/{id}/status": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Automation id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "setAutomationStatus",
        "tags": [
          "Automations"
        ],
        "summary": "Activate or pause",
        "description": "**This is the call that starts real sending.** Activating requires `confirm: true` AND passes a server-side check that every send step points at a PUBLISHED template and the lane tree is intact — a failure comes back as `template_not_published`. Pausing requires neither. Run `GET /api/v1/automations/{id}/preflight` first to see what would block.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused"
                    ],
                    "description": "`active` starts real sending; `paused` stops it.",
                    "examples": [
                      "active"
                    ]
                  },
                  "confirm": {
                    "type": "boolean",
                    "description": "Required (`true`) to activate. Pausing needs no confirmation.",
                    "examples": [
                      true
                    ]
                  }
                },
                "required": [
                  "status"
                ]
              },
              "example": {
                "status": "active",
                "confirm": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status changed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "examples": [
                        "active"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "409": {
            "description": "A send step points at an unpublished template.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "template_not_published",
                    "message": "Step 2 uses template \"win-back-2\" which is not published."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations/{id}/backfill": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Automation id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "backfillMissedEnrollments",
        "tags": [
          "Automations"
        ],
        "summary": "Catch up enrollments missed while paused",
        "description": "Events keep being recorded while an automation is paused — only enrollment is skipped — so the contacts it missed are recoverable. **Defaults to a dry run**: the point is to see who would be enrolled before committing. Contacts whose EXIT event arrived after their trigger are skipped, because they resolved during the pause and enrolling them would chase a customer who already converted; the automation's own re-enrollment, cooldown and suppression guards still apply. `since` is required and **capped at six hours** — a window reaching further back is pulled forward and `window_clamped` says so, because replaying a one-hour chase days late is noise, not recovery. Resume the automation before running for real.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "since": {
                    "type": "string",
                    "examples": [
                      "2026-07-22T11:30:00Z"
                    ]
                  },
                  "dry_run": {
                    "type": "boolean",
                    "default": true
                  },
                  "max_contacts": {
                    "type": "integer",
                    "default": 1000
                  }
                }
              },
              "example": {
                "since": "2026-07-22T11:30:00Z",
                "dry_run": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preview, or the result of the enrollment.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "dry_run": {
                      "type": "boolean"
                    },
                    "since": {
                      "type": "string",
                      "examples": [
                        "2026-07-22T11:30:00Z"
                      ]
                    },
                    "window_clamped": {
                      "type": "boolean"
                    },
                    "would_enroll": {
                      "type": "integer"
                    },
                    "enrolled": {
                      "type": "integer"
                    },
                    "skipped_already_resolved": {
                      "type": "integer"
                    },
                    "skipped_by_guards": {
                      "type": "integer"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "409": {
            "description": "Automation is paused, or too many contacts qualify.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Resume the automation before backfilling — a paused automation enrolls nobody."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations/{id}/runs": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Automation id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listAutomationRuns",
        "tags": [
          "Automations"
        ],
        "summary": "List enrollments",
        "description": "One row per contact-run, newest first: where it is in the tree and what it's waiting on.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by run status (active, completed, exited, canceled, failed).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max rows (1–100, default 50).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Runs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string",
                            "examples": [
                              "active"
                            ]
                          },
                          "contact_email": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "current_step_id": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "next_step_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "waiting_for_event": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "wait_until": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "exit_step_id": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "variant_assignments": {
                            "type": "object"
                          },
                          "cancel_reason": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "started_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "finished_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations/{id}/metrics": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Automation id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getAutomationMetrics",
        "tags": [
          "Automations"
        ],
        "summary": "Per-step funnel",
        "description": "Enrollment counts plus delivery/open/click buckets per step, and per variant where a step carries an A/B split. Steps are keyed by position label (`step 3`) so the shape survives tree edits. Defaults to the last 30 days.",
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "ISO 8601 start of the window.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Funnel.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "since": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "run_counts": {
                      "type": "object"
                    },
                    "by_step": {
                      "type": "object",
                      "description": "Keyed by `step N`."
                    },
                    "by_variant": {
                      "type": "object",
                      "description": "Keyed by `step N / variant`."
                    },
                    "ab_tests": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "step": {
                            "type": "string",
                            "examples": [
                              "step 1"
                            ]
                          },
                          "leader": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "examples": [
                              "b"
                            ]
                          },
                          "reason": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "examples": [
                              "too_close"
                            ]
                          },
                          "arms": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "variant": {
                                  "type": "string"
                                },
                                "delivered": {
                                  "type": "integer"
                                },
                                "click_rate_pct": {
                                  "type": "number"
                                },
                                "open_rate_pct": {
                                  "type": "number"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations/{id}/preflight": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Automation id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "preflightAutomation",
        "tags": [
          "Automations"
        ],
        "summary": "Pre-launch check",
        "description": "Read-only dry run of everything activation would validate: published templates, lane-tree integrity, a resolvable sender, a trigger something actually emits. `ready` reflects BLOCKING checks only. Run it in CI to catch a broken automation before anyone tries to turn it on.",
        "responses": {
          "200": {
            "description": "Check results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ready": {
                      "type": "boolean",
                      "description": "True when nothing blocking would stop activation."
                    },
                    "checks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "pass": {
                            "type": "boolean"
                          },
                          "blocking": {
                            "type": "boolean"
                          },
                          "label": {
                            "type": "string"
                          },
                          "detail": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/automations/{id}/duplicate": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Automation id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "duplicateAutomation",
        "tags": [
          "Automations"
        ],
        "summary": "Duplicate an automation",
        "description": "Copies the automation and its whole step tree under a fresh name. The copy is ALWAYS paused, whatever the source's status.",
        "responses": {
          "201": {
            "description": "Copy created, paused.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string",
                      "examples": [
                        "Win back (copy)"
                      ]
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "paused"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict — the key was used with a different body, or the first request with it is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This Idempotency-Key was already used with a different request body. Use a new key for a different request."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/api/v1/automations/{id}/ab-test": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Automation id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "setAbTest",
        "tags": [
          "Automations"
        ],
        "summary": "Set up an A/B split",
        "description": "Splits a send step across weighted template VERSIONS. Assignment is deterministic per contact-run, so a contact always sees the same arm. Pass `variants: null` to clear the split.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "position": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991,
                    "description": "Send step to split.",
                    "examples": [
                      1
                    ]
                  },
                  "variants": {
                    "anyOf": [
                      {
                        "minItems": 2,
                        "maxItems": 5,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "variantKey": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 20
                            },
                            "versionId": {
                              "type": "string",
                              "format": "uuid",
                              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                            },
                            "weight": {
                              "default": 1,
                              "type": "number",
                              "exclusiveMinimum": 0
                            }
                          },
                          "required": [
                            "variantKey",
                            "versionId"
                          ]
                        }
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Weighted template VERSIONS. Create them with `PATCH /api/v1/templates/{slug}` + `variant_key`, publish each, then attach here. `null` clears the split.",
                    "examples": [
                      [
                        {
                          "variantKey": "a",
                          "versionId": "6f2c…",
                          "weight": 1
                        },
                        {
                          "variantKey": "b",
                          "versionId": "9d41…",
                          "weight": 1
                        }
                      ]
                    ]
                  }
                },
                "required": [
                  "position",
                  "variants"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Split configured.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "position": {
                      "type": "integer",
                      "examples": [
                        1
                      ]
                    },
                    "variants": {
                      "type": [
                        "array",
                        "null"
                      ],
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation or step matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "promoteAbWinner",
        "tags": [
          "Automations"
        ],
        "summary": "Promote the winning variant",
        "description": "Makes the leading arm the step's base version and clears the split. Refused while the test is too close or too thin to call, so a winner is never declared on noise — check `ab_tests[].leader` in the metrics endpoint first.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "position": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991,
                    "description": "Send step whose winner should be promoted.",
                    "examples": [
                      1
                    ]
                  }
                },
                "required": [
                  "position"
                ]
              },
              "example": {
                "position": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Winner promoted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "position": {
                      "type": "integer",
                      "examples": [
                        1
                      ]
                    },
                    "promoted_variant": {
                      "type": "string",
                      "examples": [
                        "b"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The test can't be called yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Arms are too close to call."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No automation or step matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Automation not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/domains": {
      "post": {
        "operationId": "createDomain",
        "tags": [
          "Setup"
        ],
        "summary": "Add a sending domain",
        "description": "Registers the domain with the project's provider and returns the DNS records to publish, plus a recommended DMARC record (`dmarc.recommended_record`) — Gmail/Yahoo bulk-sender rules require DMARC on the From domain, but the provider does not, so it's advisory. A human still has to add them at the DNS host; then call the verify endpoint. Sends from an unverified domain are refused. Requires an `admin`-scope key.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 253,
                    "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$",
                    "description": "Bare domain to send from.",
                    "examples": [
                      "mail.acme.com"
                    ]
                  }
                },
                "required": [
                  "domain"
                ]
              },
              "example": {
                "domain": "mail.acme.com"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Domain registered. Publish `dns_records`, then verify.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "domain": {
                      "type": "string",
                      "examples": [
                        "mail.acme.com"
                      ]
                    },
                    "status": {
                      "type": "string",
                      "examples": [
                        "pending"
                      ]
                    },
                    "dns_records": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "examples": [
                              "TXT"
                            ]
                          },
                          "name": {
                            "type": "string"
                          },
                          "value": {
                            "type": "string"
                          },
                          "priority": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          }
                        }
                      }
                    },
                    "dmarc": {
                      "type": "object",
                      "description": "Advisory DMARC state from our own DNS check. Never blocks verification; Gmail/Yahoo bulk-sender rules require a DMARC record on the From domain.",
                      "properties": {
                        "status": {
                          "type": "string",
                          "description": "unknown (not checked / DNS error) | missing | found.",
                          "examples": [
                            "missing"
                          ]
                        },
                        "record": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "The DMARC TXT record found, if any."
                        },
                        "recommendedRecord": {
                          "type": "object",
                          "description": "Present while DMARC isn't confirmed — publish this TXT record.",
                          "properties": {
                            "type": {
                              "type": "string",
                              "examples": [
                                "TXT"
                              ]
                            },
                            "name": {
                              "type": "string",
                              "examples": [
                                "_dmarc.mail.acme.com"
                              ]
                            },
                            "value": {
                              "type": "string",
                              "examples": [
                                "v=DMARC1; p=none;"
                              ]
                            },
                            "note": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "tracking": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "Domain-level open/click tracking (Resend). Null for SendGrid — tracking is applied per send there. The tracking CNAME rides in dns_records (record: 'Tracking'); click events won't fire until it resolves.",
                      "properties": {
                        "open": {
                          "type": [
                            "boolean",
                            "null"
                          ]
                        },
                        "click": {
                          "type": [
                            "boolean",
                            "null"
                          ]
                        },
                        "subdomain": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "examples": [
                            "tk"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict — the key was used with a different body, or the first request with it is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This Idempotency-Key was already used with a different request body. Use a new key for a different request."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      },
      "get": {
        "operationId": "listDomains",
        "tags": [
          "Setup"
        ],
        "summary": "List domains",
        "responses": {
          "200": {
            "description": "Domains.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "domain": {
                            "type": "string"
                          },
                          "provider": {
                            "type": "string",
                            "examples": [
                              "resend"
                            ]
                          },
                          "status": {
                            "type": "string",
                            "examples": [
                              "verified"
                            ]
                          },
                          "verified": {
                            "type": "boolean"
                          },
                          "dns_records": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          },
                          "region": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "verified_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "last_checked_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "dmarc_status": {
                            "type": "string",
                            "description": "Advisory DMARC presence from our own DNS check: unknown | missing | found. Never affects `verified`.",
                            "examples": [
                              "found"
                            ]
                          },
                          "dmarc_record": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "dmarc_checked_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "open_tracking": {
                            "type": [
                              "boolean",
                              "null"
                            ],
                            "description": "Open/click tracking flags. Null = never read from the provider (Resend) or per-send default applies (SendGrid)."
                          },
                          "click_tracking": {
                            "type": [
                              "boolean",
                              "null"
                            ]
                          },
                          "tracking_subdomain": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "examples": [
                              "tk"
                            ]
                          }
                        }
                      }
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/domains/{domain}": {
      "parameters": [
        {
          "name": "domain",
          "in": "path",
          "required": true,
          "description": "The domain name itself, e.g. `mail.acme.com`.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "operationId": "deleteDomain",
        "tags": [
          "Setup"
        ],
        "summary": "Delete a domain",
        "description": "Removes the sending domain from this project — its sender identities go with it — and from the provider account, unless another project still uses the provider domain (then it's left in place and `warning` says so). Refused while the project's default sender is on this domain and other senders exist elsewhere. Templates and automations sending from the domain will fail until it's re-added and verified. Requires an `admin`-scope key.",
        "responses": {
          "200": {
            "description": "Domain deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domain": {
                      "type": "string",
                      "examples": [
                        "mail.acme.com"
                      ]
                    },
                    "deleted": {
                      "type": "boolean"
                    },
                    "warning": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Present when the provider copy was left in place (shared with another project) or the provider-side delete failed."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The default sender lives on this domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "The project's default sender is on this domain — make a sender on another domain the default first."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No domain matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Domain not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/domains/{domain}/verify": {
      "parameters": [
        {
          "name": "domain",
          "in": "path",
          "required": true,
          "description": "The domain name itself, e.g. `mail.acme.com`.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "verifyDomain",
        "tags": [
          "Setup"
        ],
        "summary": "Verify a domain",
        "description": "Asks the provider to re-check DNS. Poll after publishing the records — `verified: false` just means DNS hasn't propagated yet, which is normal for the first several minutes. Also re-checks DMARC and returns the advisory `dmarc` block; DMARC never blocks verification.",
        "responses": {
          "200": {
            "description": "Current verification state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domain": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "examples": [
                        "verified"
                      ]
                    },
                    "verified": {
                      "type": "boolean"
                    },
                    "dns_records": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "dmarc": {
                      "type": "object",
                      "description": "Advisory DMARC state from our own DNS check. Never blocks verification; Gmail/Yahoo bulk-sender rules require a DMARC record on the From domain.",
                      "properties": {
                        "status": {
                          "type": "string",
                          "description": "unknown (not checked / DNS error) | missing | found.",
                          "examples": [
                            "missing"
                          ]
                        },
                        "record": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "The DMARC TXT record found, if any."
                        },
                        "recommendedRecord": {
                          "type": "object",
                          "description": "Present while DMARC isn't confirmed — publish this TXT record.",
                          "properties": {
                            "type": {
                              "type": "string",
                              "examples": [
                                "TXT"
                              ]
                            },
                            "name": {
                              "type": "string",
                              "examples": [
                                "_dmarc.mail.acme.com"
                              ]
                            },
                            "value": {
                              "type": "string",
                              "examples": [
                                "v=DMARC1; p=none;"
                              ]
                            },
                            "note": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "tracking": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "Domain-level open/click tracking (Resend). Null for SendGrid — tracking is applied per send there. The tracking CNAME rides in dns_records (record: 'Tracking'); click events won't fire until it resolves.",
                      "properties": {
                        "open": {
                          "type": [
                            "boolean",
                            "null"
                          ]
                        },
                        "click": {
                          "type": [
                            "boolean",
                            "null"
                          ]
                        },
                        "subdomain": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "examples": [
                            "tk"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No domain matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Domain not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/senders": {
      "post": {
        "operationId": "createSender",
        "tags": [
          "Setup"
        ],
        "summary": "Create a sender",
        "description": "A From identity. The address must sit on a VERIFIED domain in this project. Requires an `admin`-scope key.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "from_name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "description": "Display name recipients see.",
                    "examples": [
                      "Acme"
                    ]
                  },
                  "from_email": {
                    "type": "string",
                    "format": "email",
                    "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "description": "Address on a VERIFIED domain in this project.",
                    "examples": [
                      "hello@acme.com"
                    ]
                  },
                  "reply_to": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "email",
                        "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Where replies go, if different.",
                    "examples": [
                      "support@acme.com"
                    ]
                  },
                  "make_default": {
                    "type": "boolean",
                    "description": "Use this sender when a send omits `from`."
                  }
                },
                "required": [
                  "from_name",
                  "from_email"
                ]
              },
              "example": {
                "from_name": "Acme",
                "from_email": "hello@acme.com",
                "make_default": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sender created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "from_name": {
                      "type": "string"
                    },
                    "from_email": {
                      "type": "string"
                    },
                    "is_default": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The address isn't on a verified domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "No verified domain for acme.com in this project."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict — the key was used with a different body, or the first request with it is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This Idempotency-Key was already used with a different request body. Use a new key for a different request."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      },
      "get": {
        "operationId": "listSenders",
        "tags": [
          "Setup"
        ],
        "summary": "List senders",
        "responses": {
          "200": {
            "description": "Senders, default first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "from_name": {
                            "type": "string"
                          },
                          "from_email": {
                            "type": "string"
                          },
                          "reply_to": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "is_default": {
                            "type": "boolean"
                          },
                          "domain": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "domain_verified": {
                            "type": "boolean",
                            "description": "False means sends from this identity are refused."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/senders/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Sender id.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "patch": {
        "operationId": "updateSender",
        "tags": [
          "Setup"
        ],
        "summary": "Edit a sender",
        "description": "Changes the display name, Reply-To, or which sender is the project default. `from_email` is deliberately not editable — a new address needs re-validating against a verified domain, so that's a create.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "from_name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "description": "New display name.",
                    "examples": [
                      "Acme Support"
                    ]
                  },
                  "reply_to": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "email",
                        "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "New Reply-To. null clears it."
                  },
                  "is_default": {
                    "type": "boolean",
                    "const": true,
                    "description": "Pass `true` to make this the project default (demotes the previous one)."
                  }
                }
              },
              "example": {
                "from_name": "Acme Support"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sender updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "is_default": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No sender matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Sender not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      },
      "delete": {
        "operationId": "deleteSender",
        "tags": [
          "Setup"
        ],
        "summary": "Delete a sender",
        "description": "Removes the sender identity. Refused for the default sender while other senders exist — nothing auto-promotes a new default, so promote another sender first. Templates pinning this sender fall back to the project default. Requires an `admin`-scope key.",
        "responses": {
          "200": {
            "description": "Sender deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "deleted": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "This is the default sender.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "This is the default sender — make another sender the default first."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No sender matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Sender not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/connection": {
      "get": {
        "operationId": "getConnectionStatus",
        "tags": [
          "Setup"
        ],
        "summary": "Can this project send?",
        "description": "One call for the whole readiness question: provider connected, domains verified, default sender present, webhooks registered, kill switch off. Meant as a deploy-time preflight.\n\nNote there is no way to SET a provider API key over this API — credentials only ever enter through the dashboard (`settings_url`), so a leaked `aem_` key can't repoint your sending.",
        "responses": {
          "200": {
            "description": "Setup status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ready": {
                      "type": "boolean",
                      "description": "True when this project can actually send right now."
                    },
                    "provider": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "properties": {
                        "name": {
                          "type": "string",
                          "examples": [
                            "resend"
                          ]
                        },
                        "status": {
                          "type": "string"
                        },
                        "webhook_registered": {
                          "type": "boolean"
                        },
                        "error_message": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    },
                    "domains": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Per-domain status incl. advisory `dmarc_status` (unknown | missing | found) — DMARC is not part of `ready`."
                    },
                    "senders": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "sends_paused": {
                      "type": "boolean"
                    },
                    "daily_send_cap": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "settings_url": {
                      "type": "string",
                      "description": "Where a human pastes the provider API key."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/setup/onboarding": {
      "get": {
        "operationId": "getOnboardingSteps",
        "tags": [
          "Setup"
        ],
        "summary": "How far through setup is this company?",
        "description": "The ten steps of getting a company live, with the same addresses (`1.1`–`3.5`) and titles the operator sees in the dashboard. Every `done` is derived from real rows — there is no stored checklist — so work done through this API, over MCP or by hand all move the same list.\n\nDistinct from `GET /api/v1/connection`, which answers the narrower deploy-time question 'can this project send right now'. This one also covers the discovery answers, the approved programme and whether the company has sent.",
        "responses": {
          "200": {
            "description": "Setup progress.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "phase": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "understand | strategy | content | live, or null once complete."
                    },
                    "complete": {
                      "type": "boolean"
                    },
                    "done_count": {
                      "type": "integer"
                    },
                    "total_count": {
                      "type": "integer"
                    },
                    "next": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Address of the first unfinished step, e.g. `1.5`."
                    },
                    "steps": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Each: `address`, `key`, `title`, `phase`, `done`, `in_progress`, `detail[]`."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "read",
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ]
      }
    },
    "/api/v1/webhooks/register": {
      "post": {
        "operationId": "registerWebhooks",
        "tags": [
          "Setup"
        ],
        "summary": "Register provider webhooks (deprecated)",
        "deprecated": true,
        "x-sunset": "2027-02-10T00:00:00.000Z",
        "x-deprecation-link": "https://sendandretain.com/docs/guides/connect-a-provider",
        "x-replaced-by": "POST /api/v1/setup/provider-webhook",
        "description": "**Deprecated — use `POST /api/v1/setup/provider-webhook`.** Identical behaviour; the path moved because `/api/v1/webhooks` now belongs to your OWN endpoints (see the Webhooks tag) and sharing a prefix made two unrelated things look related. This alias keeps working until the sunset date and announces itself on every response.",
        "responses": {
          "200": {
            "description": "Webhook registered.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoint": {
                      "type": "string"
                    },
                    "webhook_id": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/setup/provider-webhook": {
      "post": {
        "operationId": "registerProviderWebhook",
        "tags": [
          "Setup"
        ],
        "summary": "Register provider webhooks",
        "description": "Points the delivery provider's event webhook at this project and stores the signing secret. Without it, messages never advance past `sent` — deliveries, bounces, opens and complaints all arrive by webhook, and bounce/complaint auto-suppression depends on them. Idempotent; safe on every deploy.\n\nThis is inbound plumbing (provider → us). To receive events at your OWN endpoint, see the Webhooks tag.",
        "responses": {
          "200": {
            "description": "Webhook registered.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoint": {
                      "type": "string"
                    },
                    "webhook_id": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/webhooks": {
      "post": {
        "operationId": "createWebhookEndpoint",
        "tags": [
          "Webhooks"
        ],
        "summary": "Create a webhook endpoint",
        "description": "Registers an HTTPS endpoint to receive email events, and returns its signing secret.\n\n**The secret is shown exactly once.** There is no endpoint that returns it again — if you lose it, rotate. Verify every delivery against the RAW request body with any Standard Webhooks library (`standardwebhooks` on npm/PyPI/Go), or see the receive-webhooks guide.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "HTTPS endpoint that receives the events. Must resolve to a public address — private ranges, localhost and non-default ports are refused, and the check is repeated before every delivery.",
                    "examples": [
                      "https://hooks.acme.com/sendandretain"
                    ]
                  },
                  "event_types": {
                    "minItems": 1,
                    "maxItems": 32,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 64
                    },
                    "description": "Events to receive. Subscribe to `webhook.test` as well so you can verify the endpoint before real mail goes out.",
                    "examples": [
                      [
                        "email.delivered",
                        "email.bounced",
                        "webhook.test"
                      ]
                    ]
                  },
                  "description": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 500
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Your own label. Never sent to the endpoint.",
                    "examples": [
                      "CRM sync"
                    ]
                  }
                },
                "required": [
                  "url",
                  "event_types"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Endpoint created. `secret` appears in this response only.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "examples": [
                        "whe_9f2a1c"
                      ]
                    },
                    "url": {
                      "type": "string",
                      "examples": [
                        "https://hooks.acme.com/sendandretain"
                      ]
                    },
                    "description": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "examples": [
                        "CRM sync"
                      ]
                    },
                    "event_types": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "examples": [
                        [
                          "email.delivered",
                          "email.bounced"
                        ]
                      ]
                    },
                    "enabled": {
                      "type": "boolean"
                    },
                    "disabled_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "disabled_reason": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "`consecutive_failures` (auto-disabled after sustained failure), `manual` (you disabled it, or the endpoint returned 410 Gone), or `url_unsafe` (the URL stopped resolving to a public address)."
                    },
                    "secret_hint": {
                      "type": "string",
                      "description": "Last four characters of the signing secret, so you can tell which one is configured. The full secret is returned ONLY when the endpoint is created or its secret is rotated.",
                      "examples": [
                        "whsec_…4f9a"
                      ]
                    },
                    "consecutive_failures": {
                      "type": "integer",
                      "examples": [
                        0
                      ]
                    },
                    "last_delivery_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "last_success_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "last_error": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "secret": {
                      "type": "string",
                      "description": "Store this now — it is never returned again.",
                      "examples": [
                        "whsec_MfKQ9r8sTn3xW1yZ4bC7dE0fG2hJ5kL8"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "An endpoint with this URL already exists in this project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "An endpoint with this URL already exists in this project."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      },
      "get": {
        "operationId": "listWebhookEndpoints",
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhook endpoints",
        "description": "Every endpoint configured for this project. Secrets are never included.",
        "responses": {
          "200": {
            "description": "Endpoints.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "examples": [
                              "whe_9f2a1c"
                            ]
                          },
                          "url": {
                            "type": "string",
                            "examples": [
                              "https://hooks.acme.com/sendandretain"
                            ]
                          },
                          "description": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "examples": [
                              "CRM sync"
                            ]
                          },
                          "event_types": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "examples": [
                              [
                                "email.delivered",
                                "email.bounced"
                              ]
                            ]
                          },
                          "enabled": {
                            "type": "boolean"
                          },
                          "disabled_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "disabled_reason": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "`consecutive_failures` (auto-disabled after sustained failure), `manual` (you disabled it, or the endpoint returned 410 Gone), or `url_unsafe` (the URL stopped resolving to a public address)."
                          },
                          "secret_hint": {
                            "type": "string",
                            "description": "Last four characters of the signing secret, so you can tell which one is configured. The full secret is returned ONLY when the endpoint is created or its secret is rotated.",
                            "examples": [
                              "whsec_…4f9a"
                            ]
                          },
                          "consecutive_failures": {
                            "type": "integer",
                            "examples": [
                              0
                            ]
                          },
                          "last_delivery_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "last_success_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "last_error": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updated_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{id}": {
      "get": {
        "operationId": "getWebhookEndpoint",
        "tags": [
          "Webhooks"
        ],
        "summary": "Get a webhook endpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "examples": [
                        "whe_9f2a1c"
                      ]
                    },
                    "url": {
                      "type": "string",
                      "examples": [
                        "https://hooks.acme.com/sendandretain"
                      ]
                    },
                    "description": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "examples": [
                        "CRM sync"
                      ]
                    },
                    "event_types": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "examples": [
                        [
                          "email.delivered",
                          "email.bounced"
                        ]
                      ]
                    },
                    "enabled": {
                      "type": "boolean"
                    },
                    "disabled_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "disabled_reason": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "`consecutive_failures` (auto-disabled after sustained failure), `manual` (you disabled it, or the endpoint returned 410 Gone), or `url_unsafe` (the URL stopped resolving to a public address)."
                    },
                    "secret_hint": {
                      "type": "string",
                      "description": "Last four characters of the signing secret, so you can tell which one is configured. The full secret is returned ONLY when the endpoint is created or its secret is rotated.",
                      "examples": [
                        "whsec_…4f9a"
                      ]
                    },
                    "consecutive_failures": {
                      "type": "integer",
                      "examples": [
                        0
                      ]
                    },
                    "last_delivery_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "last_success_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "last_error": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No webhook endpoint matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Webhook endpoint not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "updateWebhookEndpoint",
        "tags": [
          "Webhooks"
        ],
        "summary": "Update a webhook endpoint",
        "description": "Change the URL, the subscription list, the label, or pause/resume delivery. `event_types` REPLACES the existing list rather than merging into it.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Replacement URL. Re-validated on save."
                  },
                  "event_types": {
                    "minItems": 1,
                    "maxItems": 32,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 64
                    },
                    "description": "Replacement subscription list. Not merged with the old one."
                  },
                  "description": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 500
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "enabled": {
                    "type": "boolean",
                    "description": "`false` pauses delivery without losing the endpoint or its secret. `true` resumes it AND clears the consecutive-failure count."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Endpoint updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "examples": [
                        "whe_9f2a1c"
                      ]
                    },
                    "url": {
                      "type": "string",
                      "examples": [
                        "https://hooks.acme.com/sendandretain"
                      ]
                    },
                    "description": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "examples": [
                        "CRM sync"
                      ]
                    },
                    "event_types": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "examples": [
                        [
                          "email.delivered",
                          "email.bounced"
                        ]
                      ]
                    },
                    "enabled": {
                      "type": "boolean"
                    },
                    "disabled_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "disabled_reason": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "`consecutive_failures` (auto-disabled after sustained failure), `manual` (you disabled it, or the endpoint returned 410 Gone), or `url_unsafe` (the URL stopped resolving to a public address)."
                    },
                    "secret_hint": {
                      "type": "string",
                      "description": "Last four characters of the signing secret, so you can tell which one is configured. The full secret is returned ONLY when the endpoint is created or its secret is rotated.",
                      "examples": [
                        "whsec_…4f9a"
                      ]
                    },
                    "consecutive_failures": {
                      "type": "integer",
                      "examples": [
                        0
                      ]
                    },
                    "last_delivery_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "last_success_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "last_error": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No webhook endpoint matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Webhook endpoint not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      },
      "delete": {
        "operationId": "deleteWebhookEndpoint",
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a webhook endpoint",
        "description": "Permanent. The delivery log goes with it. To stop delivery while keeping the endpoint and its secret, PATCH `enabled: false` instead.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Endpoint deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No webhook endpoint matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Webhook endpoint not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{id}/rotate-secret": {
      "post": {
        "operationId": "rotateWebhookSecret",
        "tags": [
          "Webhooks"
        ],
        "summary": "Rotate the signing secret",
        "description": "Mints a new signing secret and returns it once. The previous secret keeps verifying for a grace window, and BOTH sign every delivery until it expires — so you can deploy the new one without an outage. Also the recovery path for a lost secret.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "grace_minutes": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10080,
                    "description": "How long the OLD secret keeps verifying. Both secrets sign every delivery during the window, so you can deploy the new one on your own schedule. Defaults to 1440 (24h); maximum 10080 (7 days). Pass 0 to cut over immediately.",
                    "examples": [
                      1440
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rotated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string",
                      "description": "The new secret. Shown once."
                    },
                    "previous_secret_expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "After this, deliveries carry only the new signature."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No webhook endpoint matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Webhook endpoint not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{id}/test": {
      "post": {
        "operationId": "testWebhookEndpoint",
        "tags": [
          "Webhooks"
        ],
        "summary": "Send a test delivery",
        "description": "Queues a synthetic `webhook.test` event. It travels the full path — same signing, same retry curve, same delivery log — so a passing test proves real events will arrive too. Requires the endpoint to be subscribed to `webhook.test`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Test delivery queued. Poll the deliveries list for its outcome.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "delivery_id": {
                      "type": "string",
                      "examples": [
                        "whd_44b1e0"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No webhook endpoint matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Webhook endpoint not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "tags": [
          "Webhooks"
        ],
        "summary": "List deliveries",
        "description": "What we attempted, when, and what your server said. `response_snippet` carries the first 2 KB of your endpoint's response body, which is usually the whole answer. Newest first; page with `limit` + `before`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "pending | in_flight | delivered | failed | skipped.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "Deprecated — use `cursor`. ISO 8601 `created_at`: rows older than this.",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "deprecated": true,
            "x-sunset": "2027-04-05T00:00:00.000Z",
            "x-deprecation-link": "https://sendandretain.com/docs/api/pagination",
            "x-replaced-by": "?cursor="
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max rows (1–100, default 50).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Deliveries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "Also the `webhook-id` header. Stable across retries — dedupe on it.",
                            "examples": [
                              "whd_44b1e0"
                            ]
                          },
                          "event_type": {
                            "type": "string",
                            "examples": [
                              "email.delivered"
                            ]
                          },
                          "message_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "examples": [
                              "msg_3aF9c1"
                            ]
                          },
                          "status": {
                            "type": "string",
                            "description": "`pending` (queued or backing off), `in_flight`, `delivered`, `failed` (attempts exhausted), `skipped` (endpoint disabled, unsubscribed, or returned 410).",
                            "examples": [
                              "delivered"
                            ]
                          },
                          "attempt": {
                            "type": "integer",
                            "examples": [
                              1
                            ]
                          },
                          "last_status_code": {
                            "type": "integer",
                            "examples": [
                              200
                            ]
                          },
                          "last_error": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "response_snippet": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "First 2 KB of your endpoint's response body — usually the whole answer."
                          },
                          "duration_ms": {
                            "type": "integer",
                            "examples": [
                              84
                            ]
                          },
                          "next_attempt_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "delivered_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No webhook endpoint matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Webhook endpoint not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{id}/deliveries/{deliveryId}/replay": {
      "post": {
        "operationId": "replayWebhookDelivery",
        "tags": [
          "Webhooks"
        ],
        "summary": "Replay a delivery",
        "description": "Re-queues a settled delivery with the original payload, byte for byte, and the SAME `webhook-id`. A consumer that already processed it will dedupe it away — replay is for deliveries you never processed successfully. Refused while the delivery is still pending or in flight.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "description": "Delivery id (the `webhook-id` you received).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Replay queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "delivery_id": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No delivery matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Delivery not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "409": {
            "description": "The delivery is still in progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This delivery is still in progress."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/segments": {
      "post": {
        "operationId": "createSegment",
        "tags": [
          "Audience"
        ],
        "summary": "Create a segment",
        "description": "A saved filter over contact attributes and tags — a definition, not a stored list. Segments can drive `$segment_entered` automation triggers.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "description": "Unique within the project.",
                    "examples": [
                      "Pro plan, active"
                    ]
                  },
                  "description": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 500
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "filter": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string",
                          "minLength": 1
                        },
                        "op": {
                          "type": "string",
                          "enum": [
                            "eq",
                            "neq",
                            "exists",
                            "not_exists",
                            "in",
                            "gt",
                            "lt",
                            "contains",
                            "within_days",
                            "older_than_days"
                          ]
                        },
                        "value": {}
                      },
                      "required": [
                        "path",
                        "op"
                      ]
                    },
                    "description": "Conditions over contact attributes and tags. All must match.",
                    "examples": [
                      [
                        {
                          "field": "attributes.plan",
                          "op": "eq",
                          "value": "Pro"
                        }
                      ]
                    ]
                  }
                },
                "required": [
                  "name",
                  "filter"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Segment created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict — the key was used with a different body, or the first request with it is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This Idempotency-Key was already used with a different request body. Use a new key for a different request."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      },
      "get": {
        "operationId": "listSegments",
        "tags": [
          "Audience"
        ],
        "summary": "List segments",
        "responses": {
          "200": {
            "description": "Segments.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "filter": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          },
                          "member_count": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "description": "Cached; null until first refresh."
                          },
                          "count_refreshed_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updated_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/segments/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Segment id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "patch": {
        "operationId": "updateSegment",
        "tags": [
          "Audience"
        ],
        "summary": "Edit a segment",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "description": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 500
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "filter": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string",
                          "minLength": 1
                        },
                        "op": {
                          "type": "string",
                          "enum": [
                            "eq",
                            "neq",
                            "exists",
                            "not_exists",
                            "in",
                            "gt",
                            "lt",
                            "contains",
                            "within_days",
                            "older_than_days"
                          ]
                        },
                        "value": {}
                      },
                      "required": [
                        "path",
                        "op"
                      ]
                    },
                    "description": "Replacement filter. Changing it recomputes the cached member count."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Segment updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No segment matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Segment not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      },
      "delete": {
        "operationId": "deleteSegment",
        "tags": [
          "Audience"
        ],
        "summary": "Delete a segment",
        "responses": {
          "200": {
            "description": "Segment deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "deleted": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No segment matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Segment not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/segments/{id}/refresh": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Segment id or exact name.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "refreshSegmentCount",
        "tags": [
          "Audience"
        ],
        "summary": "Recompute member count",
        "description": "Re-evaluates the filter against contacts. O(contacts) and capped by a scan limit — call it after a bulk import, not on every page load.",
        "responses": {
          "200": {
            "description": "Count refreshed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "member_count": {
                      "type": "integer",
                      "examples": [
                        1284
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No segment matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Segment not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/contacts/import": {
      "post": {
        "operationId": "importContacts",
        "tags": [
          "Contacts"
        ],
        "summary": "Bulk import contacts",
        "description": "Upserts up to 1000 contacts per call. **Partial success is the contract**: every entry is attempted, and the response reports how many failed rather than rolling the batch back over one bad address. Importing does NOT enroll anyone in anything — automations trigger on events, so a bulk import is silent.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "contacts": {
                    "minItems": 1,
                    "maxItems": 1000,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string",
                          "format": "email",
                          "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                        },
                        "external_id": {
                          "anyOf": [
                            {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 255
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "attributes": {
                          "type": "object",
                          "propertyNames": {
                            "type": "string"
                          },
                          "additionalProperties": {}
                        },
                        "tags": {
                          "maxItems": 50,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 60
                          }
                        }
                      },
                      "required": [
                        "email"
                      ]
                    },
                    "description": "Up to 1000 per call. Partial success — see `failed` / `failures`."
                  }
                },
                "required": [
                  "contacts"
                ]
              },
              "example": {
                "contacts": [
                  {
                    "email": "jane@acme.com",
                    "external_id": "user_8f21",
                    "attributes": {
                      "plan": "Pro"
                    }
                  },
                  {
                    "email": "sam@acme.com",
                    "tags": [
                      "beta"
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Import finished (possibly partially).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "imported": {
                      "type": "integer",
                      "examples": [
                        2
                      ]
                    },
                    "failed": {
                      "type": "integer",
                      "examples": [
                        0
                      ]
                    },
                    "failures": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "First 10 failures only."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict — the key was used with a different body, or the first request with it is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This Idempotency-Key was already used with a different request body. Use a new key for a different request."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/api/v1/contacts/{id}/events": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Contact id.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listContactEvents",
        "tags": [
          "Contacts"
        ],
        "summary": "Contact event timeline",
        "description": "What you emitted for this contact, newest first, with the properties automation triggers matched on. The first place to look when an automation didn't enroll someone you expected.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "Filter to one event name.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max rows (1–100, default 50).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Events.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string",
                            "examples": [
                              "order.completed"
                            ]
                          },
                          "properties": {
                            "type": "object"
                          },
                          "dedupe_key": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "occurred_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "More rows exist after this page."
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `?cursor=` for the next page. Null on the last page."
                    }
                  },
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "404": {
            "description": "No contact matched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "Contact not found."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/suppressions/import": {
      "post": {
        "operationId": "importSuppressions",
        "tags": [
          "Suppressions"
        ],
        "summary": "Bulk import suppressions",
        "description": "Carry existing unsubscribes over BEFORE your first send, so people who already opted out never hear from you again. Only `manual` and `unsubscribe` are importable — bounces and complaints are facts the provider reports through webhooks, and asserting them by hand would corrupt the severity ladder.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "entries": {
                    "minItems": 1,
                    "maxItems": 1000,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string",
                          "format": "email",
                          "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                        },
                        "reason": {
                          "type": "string",
                          "enum": [
                            "manual",
                            "unsubscribe"
                          ]
                        },
                        "note": {
                          "type": "string",
                          "maxLength": 500
                        }
                      },
                      "required": [
                        "email"
                      ]
                    },
                    "description": "Up to 1000 per call. Only `manual` and `unsubscribe` reasons — bounces and complaints come from provider webhooks.",
                    "examples": [
                      [
                        {
                          "email": "optedout@example.com",
                          "reason": "unsubscribe"
                        }
                      ]
                    ]
                  }
                },
                "required": [
                  "entries"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Import finished (possibly partially).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "imported": {
                      "type": "integer",
                      "examples": [
                        2
                      ]
                    },
                    "failed": {
                      "type": "integer",
                      "examples": [
                        0
                      ]
                    },
                    "failures": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Replay": {
                "$ref": "#/components/headers/Idempotency-Replay"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict — the key was used with a different body, or the first request with it is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "This Idempotency-Key was already used with a different request body. Use a new key for a different request."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/api/v1/metrics": {
      "get": {
        "operationId": "getMetrics",
        "tags": [
          "Metrics"
        ],
        "summary": "Send funnel",
        "description": "Totals plus per-template and per-day breakdowns with rates and deliverability warnings. Rates are `null` (not 0) when the denominator is zero, so \"no data\" stays distinguishable from \"0%\". Opens and clicks are rated against DELIVERED, not sent. Defaults to the last 7 days.",
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "ISO 8601 start (default: 7 days ago).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "ISO 8601 end (default: now).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Metrics.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "period": {
                      "type": "object",
                      "properties": {
                        "since": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "until": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    },
                    "totals": {
                      "type": "object"
                    },
                    "by_template": {
                      "type": "object",
                      "description": "Keyed by template slug."
                    },
                    "by_day": {
                      "type": "object",
                      "description": "Keyed by YYYY-MM-DD."
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Deliverability tripwires, phrased as actions.",
                      "examples": [
                        [
                          "Complaint rate above 0.08% — stop and investigate before sending more."
                        ]
                      ]
                    },
                    "truncated": {
                      "type": "boolean",
                      "description": "True when the window hit the query cap — narrow it for exact numbers. Always false when `source` is `daily_rollup`, which is pre-aggregated and has no cap to hit."
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "raw",
                        "daily_rollup"
                      ],
                      "description": "Which engine answered. `raw` reads the message log directly and is exact to the second. `daily_rollup` is used once `since` reaches past the 30-day log retention window, past which the individual rows no longer exist — it is aggregated to whole UTC days, so `period` reports the snapped window rather than the one you asked for, and a warning says so. One engine always answers the whole range; the two are never mixed."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/metrics/trends": {
      "get": {
        "operationId": "getMetricsTrends",
        "tags": [
          "Metrics"
        ],
        "summary": "Daily series",
        "description": "Day-by-day counts from the pre-aggregated rollup — fast and coarse, for charting. Use `GET /api/v1/metrics` when you need exact, windowed, per-template numbers. Days with no activity are absent rather than zero-filled.",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Window length, 1–365 (default 30).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Series.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "days": {
                      "type": "integer",
                      "examples": [
                        30
                      ]
                    },
                    "series": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "day": {
                            "type": "string",
                            "examples": [
                              "2026-07-20"
                            ]
                          },
                          "sent": {
                            "type": "integer"
                          },
                          "delivered": {
                            "type": "integer"
                          },
                          "fbl_delivered": {
                            "type": "integer",
                            "description": "Delivered to inbox providers that report spam complaints (Yahoo, Outlook/Hotmail and a few others — not Gmail or iCloud). Divide `complained` by THIS, not by `sent` or `delivered`: only these recipients can produce a complaint anyone hears about, so a broader denominator reads several times low."
                          },
                          "opened": {
                            "type": "integer"
                          },
                          "clicked": {
                            "type": "integer"
                          },
                          "bounced": {
                            "type": "integer"
                          },
                          "complained": {
                            "type": "integer"
                          },
                          "unsubscribed": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "totals": {
                      "type": "object"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/queue/health": {
      "get": {
        "operationId": "getQueueHealth",
        "tags": [
          "Metrics"
        ],
        "summary": "Worker queue health",
        "description": "Scheduling is ours, not the provider's: delayed sends, automation steps and throttle-deferred messages all wait in our queue. A growing `pending_due_now` or a large `oldest_pending_age_seconds` means mail is late; `dead_letter` means some gave up entirely. Worth alerting on.",
        "responses": {
          "200": {
            "description": "Queue health.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pending_due_now": {
                      "type": "integer",
                      "examples": [
                        0
                      ]
                    },
                    "oldest_pending_age_seconds": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "processing": {
                      "type": "integer",
                      "examples": [
                        0
                      ]
                    },
                    "dead_letter": {
                      "type": "integer",
                      "examples": [
                        0
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (manage templates, contacts and automations) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "write",
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ]
      }
    },
    "/api/v1/settings": {
      "get": {
        "operationId": "getProjectSettings",
        "tags": [
          "Settings"
        ],
        "summary": "Get sending guardrails",
        "description": "The kill switch, the daily cap, the auto-UTM config, the default locale, and how many messages went out today.",
        "responses": {
          "200": {
            "description": "Settings.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project_name": {
                      "type": "string"
                    },
                    "sends_paused": {
                      "type": "boolean"
                    },
                    "daily_send_cap": {
                      "type": "integer",
                      "examples": [
                        2000
                      ]
                    },
                    "utm": {
                      "type": [
                        "object",
                        "null"
                      ]
                    },
                    "default_locale": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "sent_today": {
                      "type": "integer",
                      "examples": [
                        41
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "updateProjectSettings",
        "tags": [
          "Settings"
        ],
        "summary": "Set the kill switch, daily cap, auto-UTM tagging, or default locale",
        "description": "`sends_paused: true` stops **all** sending for this project — API, automations and copilot alike — and is re-checked on the worker path, so it stops queued mail too, not just new calls. Because of that it requires `confirm: true`; resuming does not. `utm` configures auto UTM tagging, which is **already on** with sensible defaults: send it only to change the params or to switch tagging off. `default_locale` is the fallback used to pick a template translation when neither the send call nor the contact carries a locale (null = the base template language). Requires an `admin`-scope key.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "sends_paused": {
                    "type": "boolean",
                    "description": "The kill switch. `true` stops ALL sending for this project.",
                    "examples": [
                      false
                    ]
                  },
                  "daily_send_cap": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 1000000,
                    "description": "Self-imposed daily ceiling. 0 = rely on the provider plan limit.",
                    "examples": [
                      2000
                    ]
                  },
                  "utm": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "enabled": {
                            "type": "boolean"
                          },
                          "params": {
                            "type": "object",
                            "propertyNames": {
                              "type": "string"
                            },
                            "additionalProperties": {
                              "type": "string",
                              "maxLength": 200
                            }
                          }
                        },
                        "required": [
                          "enabled",
                          "params"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Auto UTM tagging, **on by default**. `params` are appended to every external link in outgoing emails (existing URL params always win). Values may embed {{automation}}, {{step}}, {{template}}, {{variant}}, {{source}} — resolved per send, slugified, and omitted when empty. Max 10 params, lowercase snake_case keys. Send `{ \"enabled\": false, \"params\": {} }` to switch tagging off; `null` clears your override and restores the defaults.",
                    "examples": [
                      {
                        "enabled": true,
                        "params": {
                          "utm_source": "email",
                          "utm_medium": "email",
                          "utm_campaign": "{{automation}}",
                          "utm_content": "{{template}}-{{step}}",
                          "utm_term": "{{variant}}"
                        }
                      }
                    ]
                  },
                  "default_locale": {
                    "anyOf": [
                      {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 35,
                        "pattern": "^[a-z]{2,3}(-[A-Za-z0-9]{2,8})?$"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Fallback locale for template translation picks (tag like `fr` or `pt-BR`) when neither the send call nor the contact carries one. `null` clears it — sends fall back to the base template language.",
                    "examples": [
                      "fr"
                    ]
                  },
                  "confirm": {
                    "type": "boolean",
                    "description": "Required (`true`) to pause. Resuming needs no confirmation."
                  }
                }
              },
              "example": {
                "sends_paused": true,
                "confirm": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Settings updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sends_paused": {
                      "type": "boolean"
                    },
                    "daily_send_cap": {
                      "type": "integer",
                      "examples": [
                        2000
                      ]
                    },
                    "utm": {
                      "type": [
                        "object",
                        "null"
                      ]
                    },
                    "default_locale": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    },
    "/api/v1/brand": {
      "get": {
        "operationId": "getBrand",
        "tags": [
          "Settings"
        ],
        "summary": "Get the brand kit",
        "description": "The COMPANY's identity — logo, colors, fonts, voice, sign-off, footer address — plus the freeform brief. Template authoring reads this, so keeping it current is what makes generated email look like the company.",
        "responses": {
          "200": {
            "description": "Brand kit and brief.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "brand": {
                      "type": "object"
                    },
                    "website_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "updateBrand",
        "tags": [
          "Settings"
        ],
        "summary": "Update the brand kit or brief",
        "description": "Section-wise: a provided section (logo/colors/fonts/voice/signOff/footerAddress/socialLinks) wholly REPLACES the stored one; omitted sections are untouched. Pass a section empty to clear it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "brand": {
                    "type": "object",
                    "properties": {
                      "logo": {
                        "type": "object",
                        "properties": {
                          "url": {
                            "type": "string",
                            "maxLength": 500,
                            "format": "uri"
                          },
                          "width": {
                            "type": "integer",
                            "minimum": 16,
                            "maximum": 600
                          }
                        }
                      },
                      "colors": {
                        "type": "object",
                        "properties": {
                          "primary": {
                            "type": "string",
                            "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
                          },
                          "accent": {
                            "type": "string",
                            "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
                          },
                          "background": {
                            "type": "string",
                            "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
                          },
                          "text": {
                            "type": "string",
                            "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
                          },
                          "muted": {
                            "type": "string",
                            "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
                          }
                        }
                      },
                      "fonts": {
                        "type": "object",
                        "properties": {
                          "heading": {
                            "type": "string",
                            "maxLength": 200
                          },
                          "body": {
                            "type": "string",
                            "maxLength": 200
                          }
                        }
                      },
                      "voice": {
                        "type": "object",
                        "properties": {
                          "traits": {
                            "default": [],
                            "maxItems": 8,
                            "type": "array",
                            "items": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 40
                            }
                          },
                          "guidance": {
                            "default": "",
                            "type": "string",
                            "maxLength": 1500
                          }
                        }
                      },
                      "signOff": {
                        "type": "string"
                      },
                      "footerAddress": {
                        "type": "string",
                        "maxLength": 500
                      },
                      "socialLinks": {
                        "maxItems": 8,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "platform": {
                              "type": "string",
                              "enum": [
                                "website",
                                "instagram",
                                "x",
                                "linkedin",
                                "facebook",
                                "youtube",
                                "github",
                                "other"
                              ]
                            },
                            "url": {
                              "type": "string",
                              "maxLength": 500,
                              "format": "uri"
                            }
                          },
                          "required": [
                            "platform",
                            "url"
                          ]
                        }
                      }
                    },
                    "description": "Brand kit. A provided section REPLACES the stored one; omitted sections are untouched."
                  }
                },
                "required": [
                  "brand"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Brand updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "brand": {
                      "type": "object"
                    },
                    "brief_updated": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Body must be JSON."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing Authorization: Bearer <api key>."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "403": {
            "description": "The key is below `admin`. Scopes are ranked, so any tier at or above `admin` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'admin' scope (domains, senders and workspace settings) — this key has 'write' scope.",
                    "required_scope": "admin",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "429": {
            "description": "Rate limited. Back off for `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests — retry in 12s."
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "x-required-scope": "admin",
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ]
      }
    }
  }
}
