openapi: 3.1.0
info:
  title: Brew Public API v1
  version: 1.0.0
  description: |-
    Generated from the Brew app Zod contracts (`lib/<domain>/contracts.ts`). This file is the source of truth for the public API documentation.

    ## Resource paths

    Identity lives in the URL path (`/v1/analytics/sends/{sendId}`) — never in a query param or request body. Collections are plural top-level segments (`/v1/emails`); query params exist only for collection pagination + simple filters. Relationships are sub-resources (`/v1/emails/{emailId}/sends`), and non-CRUD operations are explicit action sub-paths (`/v1/automations/{automationId}/test`).

    ## Response envelopes

    - Lists: `{ data: Row[], pagination: { limit, cursor: string | null, hasMore } }` — loop `while (cursor !== null)`.
    - Get-one and writes: the bare resource (creates return `201`; async sends `202`).
    - Deletes: `{ <idField>, deleted: boolean }` — idempotent (already-gone ids resolve with `deleted: false`).
    - Errors: `{ error: { code, type, message, param?, suggestion, docs } }` — branch on the stable `code`.
    - ONE exception: `POST /v1/automations/triggers/{triggerEventId}/fire` responds with the legacy fire envelope `{ success, status, code, message, receivedAt, details }` (shared with internal webhook infrastructure).

    ## Brand scoping

    A credential is scoped either to ONE BRAND or to the whole ORGANIZATION.

    A brand-scoped credential resolves its brand automatically — send nothing. An organization-scoped credential must name the brand per request with the `X-Brand-Id` header; omitting it returns `400 BRAND_ID_REQUIRED`, because there is deliberately no default brand. Discover ids with `GET /v1/brands`.

    **No public endpoint accepts a `brandId` field** in its request body or query string — sending one returns `400 INVALID_REQUEST`. `X-Brand-Id` is a header, and the only way to name a brand.

    Resources that exist in a different brand surface as `404` (never `403`), so the API does not leak cross-brand existence; the same is true of an `X-Brand-Id` naming a brand outside your organization. `GET /v1/templates` is organization-wide. `/v1/brands` manages brands themselves and is organization-level, so it takes no `X-Brand-Id`.

    ## Idempotency

    Send an `Idempotency-Key` header (≤ 100 chars) on any POST your code might retry. Same key + same body within 24h returns the original response; same key + different body returns `409 IDEMPOTENCY_CONFLICT`.
  contact:
    name: Brew Support
    url: https://docs.brew.new
    email: support@brew.new
servers:
  - url: https://brew.new/api
    description: Production
  - url: http://localhost:3000/api
    description: Local development
security:
  - bearerAuth: []
  - apiKeyAuth: []
tags:
  - name: Emails
    description: "Email designs and sending. Generate a design with the Brew email agent, edit, version, restore — then send it: `POST /v1/sends` delivers a design to a target (a saved audience, an inline list, or a single address) via a verified domain, and `POST /v1/sends` with `test: true` fires a one-off test. Sending is not campaign-specific. Send reads (list, status, per-send event feeds) live under Analytics (`/v1/analytics/sends`)."
  - name: Brands
    description: "Brand lifecycle for ORGANIZATION-scoped credentials: list the brands a credential can reach, read one, and create a new one (extraction runs asynchronously — poll `GET /v1/brands/{brandId}` until `status: completed`). These endpoints act on the organization, so they take no `X-Brand-Id`."
  - name: Analytics
    description: "Read-only cross-resource analytics: lifetime per-campaign KPIs, windowed automation performance, the unified event feed, send reads (`/v1/analytics/sends`), and the fired-trigger audit log (`/v1/analytics/trigger-instances`)."
  - name: Automations
    description: Automation graphs — deterministic create from explicit `nodes` + `connections`, update, version, publish / unpublish, test. Includes trigger event definitions + the fire endpoint (`/v1/automations/triggers`) and run history (`/v1/automations/runs`).
  - name: Contacts
    description: Create, search, patch, and delete contacts. Email is the primary key.
  - name: Contact Fields
    description: List, create, and delete custom contact field definitions.
  - name: Audiences
    description: Saved contact filter sets — a recipient target for sends.
  - name: Domains
    description: "Sending domains: add, read DNS records, verify, configure sender defaults."
  - name: Templates
    description: Public template gallery (read-only) usable as generation references.
  - name: Brand
    description: The single brand bound to the API key.
  - name: Chats
    description: Read a brand-scoped digest of a Brew chat — referenced emails/automations/triggers + a trimmed transcript — so an external agent can resume the conversation.
  - name: Integrations
    description: Brand-scoped catalog of connectable providers plus which ones are already connected. Connect itself stays in Settings (`/integrations/{provider}`).
  - name: API Keys
    description: Mint, list, and revoke API keys. `POST` body `brandId` is the new key's binding (the only v1 body field named `brandId`). Organization-wide keys need an org-admin session or an organization-scoped credential.
  - name: Meta
    description: "Public discovery surface (no auth): the machine-readable API catalog (`/v1/help`)."
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: "Send your Brew API key as `Authorization: Bearer brew_xxx`."
      x-default: Bearer brew_your_api_key
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: "Send your Brew API key as `X-API-Key: brew_xxx`."
      x-default: brew_your_api_key
  schemas:
    EmailSummary:
      type: object
      properties:
        emailId:
          type: string
          minLength: 1
        emailVersionId:
          type: string
          minLength: 1
        title:
          type: string
          minLength: 1
        status:
          type: string
          enum:
            - streaming
            - complete
            - error
        previewImage:
          type: string
          format: uri
        updatedAt:
          type: string
          format: date-time
        subjectLine:
          type: string
          description: The design's default inbox subject, persisted on the latest version. Distinct from `title` (canvas name). Detail-only; absent on rows where it has never been set (via the write surfaces' `subjectLine` field, or in-app). `POST /v1/sends` still requires an explicit `subject`.
        previewText:
          type: string
          description: The design's inbox preview line, read directly from the latest version's JSX <Preview> (its single source of truth) — what a send delivers when no explicit `previewText` override is passed to POST /v1/sends. Detail-only; absent when the design has no <Preview>.
        html:
          type: string
        versions:
          type: array
          items:
            type: object
            properties:
              version:
                anyOf:
                  - type: integer
                    minimum: 0
                  - type: string
                    enum:
                      - latest
              emailVersionId:
                type: string
                minLength: 1
            required:
              - version
              - emailVersionId
            additionalProperties: false
        group:
          type:
            - object
            - "null"
          properties:
            groupId:
              type: string
              minLength: 1
              maxLength: 64
            groupName:
              type: string
              minLength: 1
              maxLength: 60
          required:
            - groupId
            - groupName
          additionalProperties: false
      required:
        - emailId
        - title
        - status
        - updatedAt
        - group
      additionalProperties: false
    EmailGroupSummary:
      type: object
      properties:
        groupId:
          type: string
          minLength: 1
          maxLength: 64
        groupName:
          type: string
          minLength: 1
          maxLength: 60
        emailCount:
          type: integer
          minimum: 0
      required:
        - groupId
        - groupName
        - emailCount
      additionalProperties: false
    Send:
      type: object
      properties:
        sendId:
          type: string
          minLength: 1
        kind:
          type: string
          enum:
            - campaign
            - automation
            - transactional
        messageClass:
          type: string
          enum:
            - marketing
            - transactional
        transactionId:
          type: string
          minLength: 1
        emailId:
          type: string
          minLength: 1
        emailVersionId:
          type: string
          minLength: 1
        status:
          type: string
          enum:
            - scheduled
            - queued
            - sending
            - paused
            - sent
            - partially_sent
            - failed
            - canceled
        approvalState:
          type: string
          enum:
            - pending
            - approved
            - rejected
        subject:
          type: string
        previewText:
          type: string
        fromAddress:
          type: string
        senderName:
          type: string
        replyTo:
          type: string
        domainId:
          type: string
        audienceId:
          type: string
          minLength: 1
        audienceName:
          type: string
          minLength: 1
        recipientCount:
          type: integer
          minimum: 0
        runId:
          type: string
          minLength: 1
        scheduledAt:
          type: string
          format: date-time
        startedAt:
          type: string
          format: date-time
        completedAt:
          type: string
          format: date-time
        failedAt:
          type: string
          format: date-time
        error:
          type: string
        stats:
          type: object
          properties:
            sent:
              type: integer
              minimum: 0
            delivered:
              type: integer
              minimum: 0
            opened:
              type: integer
              minimum: 0
            clicked:
              type: integer
              minimum: 0
            bounced:
              type: integer
              minimum: 0
            complained:
              type: integer
              minimum: 0
            unsubscribed:
              type: integer
              minimum: 0
          required:
            - sent
            - delivered
            - opened
            - clicked
            - bounced
            - complained
            - unsubscribed
          additionalProperties: false
        delivery:
          type: object
          properties:
            accepted:
              type: integer
              minimum: 0
            pending:
              type: integer
              minimum: 0
            delayed:
              type: integer
              minimum: 0
            delivered:
              type: integer
              minimum: 0
            bounced:
              type: integer
              minimum: 0
            failed:
              type: integer
              minimum: 0
            providerSuppressed:
              type: integer
              minimum: 0
            preSendSkipped:
              type: integer
              minimum: 0
            renderFailed:
              type: integer
              minimum: 0
            updatedAt:
              type: string
              format: date-time
          required:
            - accepted
            - pending
            - delayed
            - delivered
            - bounced
            - failed
            - providerSuppressed
            - preSendSkipped
            - renderFailed
            - updatedAt
          additionalProperties: false
        gradualSend:
          type: object
          properties:
            startingPercentage:
              type: number
              minimum: 0.1
              maximum: 100
            incrementPercentage:
              type: number
              minimum: 0
              maximum: 100
            interval:
              oneOf:
                - type: object
                  properties:
                    value:
                      type: integer
                      minimum: 1
                      maximum: 24
                    unit:
                      type: string
                      enum:
                        - hour
                  required:
                    - value
                    - unit
                  additionalProperties: false
                - type: object
                  properties:
                    value:
                      type: integer
                      minimum: 1
                      maximum: 30
                    unit:
                      type: string
                      enum:
                        - day
                  required:
                    - value
                    - unit
                  additionalProperties: false
            timeZone:
              type: string
              minLength: 1
              description: IANA timezone used to preserve local wall-clock time for day intervals.
            rampEndsAt:
              type: string
              format: date-time
            currentTranche:
              type: integer
              exclusiveMinimum: 0
            sentSoFar:
              type: integer
              minimum: 0
            pausedAt:
              type: string
              format: date-time
            pauseReason:
              type: string
              enum:
                - manual
            resumedAt:
              type: string
              format: date-time
          required:
            - startingPercentage
            - incrementPercentage
            - interval
            - timeZone
          additionalProperties: false
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        events:
          type: array
          items:
            type: object
            properties:
              eventType:
                type: string
                enum:
                  - sent
                  - delivered
                  - delivery_delayed
                  - opened
                  - clicked
                  - bounced
                  - complained
                  - failed
                  - provider_suppressed
                  - suppressed
                  - quota_skipped
                  - received
                  - unsubscribed
              occurredAt:
                type: string
                format: date-time
              recipientEmail:
                type: string
              url:
                type: string
              machineGenerated:
                type: boolean
              clickBotReason:
                type: string
            required:
              - eventType
              - occurredAt
            additionalProperties: false
      required:
        - sendId
        - kind
        - emailId
        - status
        - createdAt
        - updatedAt
      additionalProperties: false
    SendEvent:
      type: object
      properties:
        eventType:
          type: string
          enum:
            - sent
            - delivered
            - delivery_delayed
            - opened
            - clicked
            - bounced
            - complained
            - failed
            - provider_suppressed
            - suppressed
            - quota_skipped
            - received
            - unsubscribed
        occurredAt:
          type: string
          format: date-time
        recipientEmail:
          type: string
        url:
          type: string
        machineGenerated:
          type: boolean
        clickBotReason:
          type: string
      required:
        - eventType
        - occurredAt
      additionalProperties: false
    TransactionalEmail:
      type: object
      properties:
        transactionId:
          type: string
          minLength: 1
        emailId:
          type: string
          minLength: 1
        emailVersionId:
          type: string
          minLength: 1
        domainId:
          type: string
          minLength: 1
        replyTo:
          type: string
        senderName:
          type: string
        fromEmail:
          type: string
        subject:
          type: string
          minLength: 1
        previewText:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        variables:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                minLength: 1
              type:
                type: string
                minLength: 1
              fallback:
                type:
                  - string
                  - "null"
            required:
              - name
              - type
              - fallback
            additionalProperties: false
        templating:
          type: object
          properties:
            engine:
              type: string
              enum:
                - legacy
                - liquid
            valid:
              type: boolean
            errors:
              type: array
              items:
                type: object
                properties:
                  source:
                    type: string
                    enum:
                      - body
                      - subject
                      - previewText
                  message:
                    type: string
                  line:
                    type: number
                  col:
                    type: number
                required:
                  - source
                  - message
                additionalProperties: false
          required:
            - engine
            - valid
            - errors
          additionalProperties: false
        variableTree:
          type: array
          items:
            $ref: "#/components/schemas/TransactionalVariableTreeNode"
        examplePayload:
          type: object
          additionalProperties:
            $ref: "#/components/schemas/TransactionalPayloadValue"
        skill:
          type: string
      required:
        - transactionId
        - emailId
        - emailVersionId
        - domainId
        - subject
        - createdAt
        - updatedAt
        - variables
      additionalProperties: false
    TransactionalVariableTreeNode:
      type: object
      properties:
        key:
          type: string
          minLength: 1
        path:
          type: string
          minLength: 1
        kind:
          type: string
          enum:
            - scalar
            - array
            - object
        fallback:
          type:
            - string
            - "null"
        namespace:
          type: string
          enum:
            - trigger
            - customer
            - other
        children:
          type: array
          items:
            $ref: "#/components/schemas/TransactionalVariableTreeNode"
        inferredType:
          type: string
          enum:
            - string
            - number
            - boolean
        usedIn:
          type: array
          items:
            type: string
            enum:
              - body
              - subject
              - previewText
      required:
        - key
        - path
        - kind
        - fallback
        - namespace
        - children
      additionalProperties: false
    TransactionalPayloadValue:
      anyOf:
        - type: string
        - type: number
        - type: boolean
        - type: "null"
        - type: array
          items:
            oneOf:
              - $ref: "#/components/schemas/TransactionalPayloadValue"
              - type: "null"
          maxItems: 250
        - type: object
          additionalProperties:
            oneOf:
              - $ref: "#/components/schemas/TransactionalPayloadValue"
              - type: "null"
    AutomationNode:
      oneOf:
        - type: object
          properties:
            id:
              type: string
              minLength: 1
            label:
              type: string
              minLength: 1
            description:
              type: string
            type:
              type: string
              enum:
                - trigger
            config:
              anyOf:
                - type: object
                  properties:
                    actionType:
                      type: string
                    eventName:
                      type: string
                    mode:
                      type: string
                      enum:
                        - event
                    triggerEventId:
                      type: string
                  additionalProperties: false
                - type: object
                  properties:
                    actionType:
                      type: string
                    eventName:
                      type: string
                    mode:
                      type: string
                      enum:
                        - manualAudience
                    audienceId:
                      type: string
                  required:
                    - mode
                    - audienceId
                  additionalProperties: false
          required:
            - id
            - label
            - type
            - config
          additionalProperties: false
        - type: object
          properties:
            id:
              type: string
              minLength: 1
            label:
              type: string
              minLength: 1
            description:
              type: string
            type:
              type: string
              enum:
                - sendEmail
            config:
              type: object
              properties:
                actionType:
                  type: string
                  description: Informational duplicate of node.type; ignored.
                emailId:
                  type: string
                  minLength: 1
                  description: Email design id — required for sendEmail.
                emailVersionId:
                  type: string
                  minLength: 1
                  description: Exact email version id for deterministic delivery — required.
                domainId:
                  type: string
                  minLength: 1
                  description: Owned, verified sending-domain id — optional at authoring; required at publish / live run.
                subject:
                  type: string
                  minLength: 1
                  description: Inbox subject — required. Supports {{var | fallback}} interpolation.
                previewText:
                  type: string
                  description: Inbox preheader — optional; the email design's <Preview> is the source of truth and wins when present.
                messageClass:
                  type: string
                  enum:
                    - marketing
                    - transactional
                  description: Leftover snapshot; ignored at delivery — the class comes from the sending domain’s purpose (automations always send marketing-class mail).
                fromName:
                  type: string
                  minLength: 1
                  description: Sender display name; resolved from the domain default when unset.
                replyTo:
                  type: string
                  format: email
                  description: Reply-to address; resolved from the domain default when unset.
                emailTitle:
                  type: string
                  description: Informational email title mirror; tolerated for round-trips.
                fromAddress:
                  type: string
                  description: Sender address on a verified sending domain; resolved from the domain default when unset.
              required:
                - emailId
                - emailVersionId
                - subject
              additionalProperties: false
          required:
            - id
            - label
            - type
            - config
          additionalProperties: false
        - type: object
          properties:
            id:
              type: string
              minLength: 1
            label:
              type: string
              minLength: 1
            description:
              type: string
            type:
              type: string
              enum:
                - wait
            config:
              type: object
              properties:
                actionType:
                  type: string
                duration:
                  type: number
                unit:
                  type: string
                  enum:
                    - ms
                    - seconds
                    - minutes
                    - hours
                    - days
                    - weeks
              required:
                - duration
                - unit
          required:
            - id
            - label
            - type
            - config
          additionalProperties: false
        - type: object
          properties:
            id:
              type: string
              minLength: 1
            label:
              type: string
              minLength: 1
            description:
              type: string
            type:
              type: string
              enum:
                - filter
            config:
              anyOf:
                - type: object
                  properties:
                    actionType:
                      type: string
                    mode:
                      type: string
                      enum:
                        - payload
                    logicalOperator:
                      type: string
                      enum:
                        - AND
                        - OR
                    conditions:
                      type: array
                      items:
                        anyOf:
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - string
                              operator:
                                type: string
                                enum:
                                  - equals
                                  - not_equals
                                  - contains
                                  - not_contains
                                  - starts_with
                                  - ends_with
                              value:
                                type: string
                                description: String value to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - number
                              operator:
                                type: string
                                enum:
                                  - equals
                                  - not_equals
                                  - gt
                                  - gte
                                  - lt
                                  - lte
                              value:
                                type: number
                                description: Finite numeric value to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - date
                              operator:
                                type: string
                                enum:
                                  - equals
                                  - not_equals
                                  - gt
                                  - gte
                                  - lt
                                  - lte
                              value:
                                anyOf:
                                  - type: string
                                    minLength: 1
                                  - type: number
                                description: ISO date string or Unix timestamp in milliseconds to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - string
                              operator:
                                type: string
                                enum:
                                  - in
                                  - not_in
                                  - contains_any
                                  - not_contains_any
                              value:
                                type: array
                                items:
                                  type: string
                                  minLength: 1
                                minItems: 1
                                description: Non-empty array of string values to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - number
                              operator:
                                type: string
                                enum:
                                  - in
                                  - not_in
                              value:
                                type: array
                                items:
                                  type: number
                                minItems: 1
                                description: Non-empty array of finite numbers to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - number
                              operator:
                                type: string
                                enum:
                                  - between
                              value:
                                type: array
                                prefixItems:
                                  - type: number
                                  - type: number
                                description: Inclusive [minimum, maximum] numeric bounds.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - date
                              operator:
                                type: string
                                enum:
                                  - between
                              value:
                                type: array
                                prefixItems:
                                  - anyOf:
                                      - type: string
                                        minLength: 1
                                      - type: number
                                  - anyOf:
                                      - type: string
                                        minLength: 1
                                      - type: number
                                description: Inclusive [start, end] ISO-date or Unix-millisecond timestamp bounds.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - string
                              operator:
                                type: string
                                enum:
                                  - is_empty
                                  - is_not_empty
                                description: Unary empty check; do not provide a value.
                            required:
                              - field
                              - type
                              - operator
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - number
                              operator:
                                type: string
                                enum:
                                  - is_empty
                                  - is_not_empty
                                description: Unary empty check; do not provide a value.
                            required:
                              - field
                              - type
                              - operator
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - date
                              operator:
                                type: string
                                enum:
                                  - is_empty
                                  - is_not_empty
                                description: Unary empty check; do not provide a value.
                            required:
                              - field
                              - type
                              - operator
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - bool
                              operator:
                                type: string
                                enum:
                                  - is_true
                                  - is_false
                                description: Unary boolean check; do not provide a value.
                            required:
                              - field
                              - type
                              - operator
                            additionalProperties: false
                      minItems: 1
                  required:
                    - logicalOperator
                    - conditions
                  additionalProperties: false
                - type: object
                  properties:
                    actionType:
                      type: string
                    mode:
                      type: string
                      enum:
                        - engagement
                    sourceNodeId:
                      type: string
                      minLength: 1
                      description: Id of the upstream sendEmail node this filter watches for opens/clicks.
                    window:
                      type: object
                      properties:
                        duration:
                          type: number
                          minimum: 0
                        unit:
                          type: string
                          enum:
                            - ms
                            - seconds
                            - minutes
                            - hours
                            - days
                            - weeks
                      required:
                        - duration
                        - unit
                      additionalProperties: false
                    branches:
                      type: array
                      items:
                        type: object
                        properties:
                          id:
                            type: string
                          label:
                            type: string
                          condition:
                            type: object
                            properties:
                              kind:
                                type: string
                                enum:
                                  - engaged
                                  - not_engaged
                                  - clicked_link
                              events:
                                type: string
                                enum:
                                  - opened
                                  - clicked
                                  - opened_or_clicked
                              url:
                                type: string
                              position:
                                type: string
                                enum:
                                  - any
                                  - first
                                  - last
                            required:
                              - kind
                        required:
                          - id
                          - condition
                      minItems: 1
                  required:
                    - mode
                    - sourceNodeId
                    - window
                    - branches
                  additionalProperties: false
          required:
            - id
            - label
            - type
            - config
          additionalProperties: false
        - type: object
          properties:
            id:
              type: string
              minLength: 1
            label:
              type: string
              minLength: 1
            description:
              type: string
            type:
              type: string
              enum:
                - split
            config:
              oneOf:
                - type: object
                  properties:
                    actionType:
                      type: string
                    mode:
                      type: string
                      enum:
                        - percentage
                    leftLabel:
                      type: string
                    rightLabel:
                      type: string
                    leftPercentage:
                      type: number
                      minimum: 0
                      maximum: 100
                    seed:
                      type: string
                  required:
                    - mode
                    - leftLabel
                    - rightLabel
                    - leftPercentage
                  additionalProperties: false
                - type: object
                  properties:
                    actionType:
                      type: string
                    mode:
                      type: string
                      enum:
                        - condition
                    leftLabel:
                      type: string
                    rightLabel:
                      type: string
                    logicalOperator:
                      type: string
                      enum:
                        - AND
                        - OR
                    conditions:
                      type: array
                      items:
                        anyOf:
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - string
                              operator:
                                type: string
                                enum:
                                  - equals
                                  - not_equals
                                  - contains
                                  - not_contains
                                  - starts_with
                                  - ends_with
                              value:
                                type: string
                                description: String value to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - number
                              operator:
                                type: string
                                enum:
                                  - equals
                                  - not_equals
                                  - gt
                                  - gte
                                  - lt
                                  - lte
                              value:
                                type: number
                                description: Finite numeric value to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - date
                              operator:
                                type: string
                                enum:
                                  - equals
                                  - not_equals
                                  - gt
                                  - gte
                                  - lt
                                  - lte
                              value:
                                anyOf:
                                  - type: string
                                    minLength: 1
                                  - type: number
                                description: ISO date string or Unix timestamp in milliseconds to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - string
                              operator:
                                type: string
                                enum:
                                  - in
                                  - not_in
                                  - contains_any
                                  - not_contains_any
                              value:
                                type: array
                                items:
                                  type: string
                                  minLength: 1
                                minItems: 1
                                description: Non-empty array of string values to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - number
                              operator:
                                type: string
                                enum:
                                  - in
                                  - not_in
                              value:
                                type: array
                                items:
                                  type: number
                                minItems: 1
                                description: Non-empty array of finite numbers to compare against.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - number
                              operator:
                                type: string
                                enum:
                                  - between
                              value:
                                type: array
                                prefixItems:
                                  - type: number
                                  - type: number
                                description: Inclusive [minimum, maximum] numeric bounds.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - date
                              operator:
                                type: string
                                enum:
                                  - between
                              value:
                                type: array
                                prefixItems:
                                  - anyOf:
                                      - type: string
                                        minLength: 1
                                      - type: number
                                  - anyOf:
                                      - type: string
                                        minLength: 1
                                      - type: number
                                description: Inclusive [start, end] ISO-date or Unix-millisecond timestamp bounds.
                            required:
                              - field
                              - type
                              - operator
                              - value
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - string
                              operator:
                                type: string
                                enum:
                                  - is_empty
                                  - is_not_empty
                                description: Unary empty check; do not provide a value.
                            required:
                              - field
                              - type
                              - operator
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - number
                              operator:
                                type: string
                                enum:
                                  - is_empty
                                  - is_not_empty
                                description: Unary empty check; do not provide a value.
                            required:
                              - field
                              - type
                              - operator
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - date
                              operator:
                                type: string
                                enum:
                                  - is_empty
                                  - is_not_empty
                                description: Unary empty check; do not provide a value.
                            required:
                              - field
                              - type
                              - operator
                            additionalProperties: false
                          - type: object
                            properties:
                              field:
                                type: string
                                minLength: 1
                                description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                              type:
                                type: string
                                enum:
                                  - bool
                              operator:
                                type: string
                                enum:
                                  - is_true
                                  - is_false
                                description: Unary boolean check; do not provide a value.
                            required:
                              - field
                              - type
                              - operator
                            additionalProperties: false
                      minItems: 1
                  required:
                    - mode
                    - leftLabel
                    - rightLabel
                    - logicalOperator
                    - conditions
                  additionalProperties: false
          required:
            - id
            - label
            - type
            - config
          additionalProperties: false
    AutomationConnection:
      type: object
      properties:
        from:
          type: string
          minLength: 1
        to:
          type: string
          minLength: 1
        branch:
          type: string
          minLength: 1
      required:
        - from
        - to
      additionalProperties: false
    AutomationRow:
      type: object
      properties:
        automationId:
          type: string
          minLength: 1
          maxLength: 64
        automationVersionId:
          type: string
          minLength: 1
          maxLength: 64
        triggerEventId:
          type: string
          minLength: 1
          maxLength: 256
        name:
          type: string
          minLength: 1
          maxLength: 120
        description:
          type: string
          maxLength: 2000
        version:
          anyOf:
            - type: integer
              minimum: 0
            - type: string
              enum:
                - latest
        published:
          type: boolean
        isLive:
          type: boolean
        liveVersion:
          anyOf:
            - type: integer
              minimum: 0
            - type: string
              enum:
                - latest
        liveAutomationVersionId:
          type: string
          minLength: 1
          maxLength: 64
        warnings:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
              message:
                type: string
            required:
              - code
              - message
            additionalProperties: false
        paused:
          type: boolean
        pausedAt:
          type: number
        nodes:
          type: array
          items:
            oneOf:
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - trigger
                  config:
                    anyOf:
                      - type: object
                        properties:
                          actionType:
                            type: string
                          eventName:
                            type: string
                          mode:
                            type: string
                            enum:
                              - event
                          triggerEventId:
                            type: string
                        additionalProperties: false
                      - type: object
                        properties:
                          actionType:
                            type: string
                          eventName:
                            type: string
                          mode:
                            type: string
                            enum:
                              - manualAudience
                          audienceId:
                            type: string
                        required:
                          - mode
                          - audienceId
                        additionalProperties: false
                required:
                  - id
                  - label
                  - type
                  - config
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - sendEmail
                  config:
                    type: object
                    properties:
                      actionType:
                        type: string
                      emailId:
                        type: string
                      emailVersionId:
                        type: string
                      emailTitle:
                        type: string
                      subject:
                        type: string
                      previewText:
                        type: string
                      messageClass:
                        type: string
                        enum:
                          - marketing
                          - transactional
                      fromName:
                        type: string
                      fromAddress:
                        type: string
                      domainId:
                        type: string
                      replyTo:
                        type: string
                      to: {}
                      html:
                        type: string
                      variables:
                        type: object
                        additionalProperties: {}
                required:
                  - id
                  - label
                  - type
                  - config
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - wait
                  config:
                    type: object
                    properties:
                      actionType:
                        type: string
                      duration:
                        type: number
                      unit:
                        type: string
                        enum:
                          - ms
                          - seconds
                          - minutes
                          - hours
                          - days
                          - weeks
                    required:
                      - duration
                      - unit
                required:
                  - id
                  - label
                  - type
                  - config
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - filter
                  config:
                    anyOf:
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - payload
                          logicalOperator:
                            type: string
                            enum:
                              - AND
                              - OR
                          conditions:
                            type: array
                            items:
                              type: object
                              properties:
                                field:
                                  type: string
                                operator:
                                  type: string
                                value:
                                  anyOf:
                                    - type: string
                                    - type: number
                                    - type: boolean
                                    - type: array
                                      items:
                                        anyOf:
                                          - type: string
                                          - type: number
                                type:
                                  type: string
                                  enum:
                                    - string
                                    - number
                                    - date
                                    - bool
                              required:
                                - field
                                - operator
                        required:
                          - logicalOperator
                          - conditions
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - engagement
                          sourceNodeId:
                            type: string
                          window:
                            type: object
                            properties:
                              duration:
                                type: number
                              unit:
                                type: string
                                enum:
                                  - ms
                                  - seconds
                                  - minutes
                                  - hours
                                  - days
                                  - weeks
                            required:
                              - duration
                              - unit
                          branches:
                            type: array
                            items:
                              type: object
                              properties:
                                id:
                                  type: string
                                label:
                                  type: string
                                condition:
                                  type: object
                                  properties:
                                    kind:
                                      type: string
                                      enum:
                                        - engaged
                                        - not_engaged
                                        - clicked_link
                                    events:
                                      type: string
                                      enum:
                                        - opened
                                        - clicked
                                        - opened_or_clicked
                                    url:
                                      type: string
                                    position:
                                      type: string
                                      enum:
                                        - any
                                        - first
                                        - last
                                  required:
                                    - kind
                              required:
                                - id
                                - condition
                        required:
                          - mode
                          - sourceNodeId
                          - window
                          - branches
                required:
                  - id
                  - label
                  - type
                  - config
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - split
                  config:
                    oneOf:
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - percentage
                          leftLabel:
                            type: string
                          rightLabel:
                            type: string
                          leftPercentage:
                            type: number
                          seed:
                            type: string
                        required:
                          - mode
                          - leftLabel
                          - rightLabel
                          - leftPercentage
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - condition
                          leftLabel:
                            type: string
                          rightLabel:
                            type: string
                          logicalOperator:
                            type: string
                            enum:
                              - AND
                              - OR
                          conditions:
                            type: array
                            items:
                              type: object
                              properties:
                                field:
                                  type: string
                                operator:
                                  type: string
                                value:
                                  anyOf:
                                    - type: string
                                    - type: number
                                    - type: boolean
                                    - type: array
                                      items:
                                        anyOf:
                                          - type: string
                                          - type: number
                                type:
                                  type: string
                                  enum:
                                    - string
                                    - number
                                    - date
                                    - bool
                              required:
                                - field
                                - operator
                        required:
                          - mode
                          - leftLabel
                          - rightLabel
                          - logicalOperator
                          - conditions
                required:
                  - id
                  - label
                  - type
                  - config
        connections:
          type: array
          items:
            type: object
            properties:
              from:
                type: string
                minLength: 1
              to:
                type: string
                minLength: 1
              branch:
                type: string
            required:
              - from
              - to
        emailIds:
          type: array
          items:
            type: string
            minLength: 1
            maxLength: 64
        createdBy:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        publishedAt:
          type: string
          format: date-time
        versions:
          type: array
          items:
            type: object
            properties:
              version:
                anyOf:
                  - type: integer
                    minimum: 0
                  - type: string
                    enum:
                      - latest
              automationVersionId:
                type: string
                minLength: 1
                maxLength: 64
            required:
              - version
              - automationVersionId
            additionalProperties: false
      required:
        - automationId
        - automationVersionId
        - name
        - version
        - published
        - emailIds
      additionalProperties: false
    AutomationDryRunReport:
      type: object
      properties:
        valid:
          type: boolean
          description: Whether the graph would publish cleanly. false when any `blockers[]` entry or any `blockingIssues[]` entry is present.
        blockers:
          type: array
          items:
            type: object
            properties:
              nodeId:
                type: string
                description: Id of the offending node. Absent on graph-level findings.
              nodeLabel:
                type: string
                description: Label of the offending node. Absent on graph-level findings.
              severity:
                type: string
                enum:
                  - error
                  - warning
              message:
                type: string
                description: Human-readable description of the finding.
            required:
              - severity
              - message
            additionalProperties: false
          description: 'Publish blockers (`severity: "error"`). Publishing fails while any remain.'
        warnings:
          type: array
          items:
            type: object
            properties:
              nodeId:
                type: string
                description: Id of the offending node. Absent on graph-level findings.
              nodeLabel:
                type: string
                description: Label of the offending node. Absent on graph-level findings.
              severity:
                type: string
                enum:
                  - error
                  - warning
              message:
                type: string
                description: Human-readable description of the finding.
            required:
              - severity
              - message
            additionalProperties: false
          description: 'Advisory findings (`severity: "warning"`). Publishing succeeds despite them.'
        blockingIssues:
          type: array
          items:
            type: object
            properties:
              nodeId:
                type: string
              nodeLabel:
                type: string
              surface:
                type: string
                enum:
                  - triggerBinding
                  - subject
                  - previewText
                  - fromName
                  - replyTo
                  - emailBody
                  - filterCondition
                  - splitCondition
                description: Where on the node the orphaned reference lives.
              variable:
                type: string
                description: The bare variable / field name that cannot be resolved.
              reason:
                type: string
                description: Short user-facing reason.
              fatal:
                type: boolean
                description: "true — filter/split conditions and triple-brace `{{{ }}}` body tokens: the run genuinely breaks, and publish fails. false — subject/previewText/fromName/replyTo and double-brace body tags: the value renders empty at send time; advisory only."
              hasFallback:
                type: boolean
                description: The token carries an inline `{{ name | fallback }}` fallback, so it renders the fallback rather than empty. Never blocks publish.
            required:
              - nodeId
              - nodeLabel
              - surface
              - variable
              - reason
              - fatal
              - hasFallback
            additionalProperties: false
          description: Trigger-payload / draft-variable compatibility findings. Present (possibly empty) on POST and PATCH dry-run responses. `valid` is false when any entry is present.
        nodeCounts:
          type: object
          properties:
            sendEmail:
              type: integer
              minimum: 0
            wait:
              type: integer
              minimum: 0
            filter:
              type: integer
              minimum: 0
            split:
              type: integer
              minimum: 0
          required:
            - sendEmail
            - wait
            - filter
            - split
          additionalProperties: false
          description: Per-kind node counts of the validated graph.
      required:
        - valid
        - blockers
        - warnings
        - nodeCounts
      additionalProperties: false
    AutomationRunRow:
      type: object
      properties:
        automationRunId:
          type: string
          minLength: 1
          maxLength: 64
        automationId:
          type: string
          minLength: 1
          maxLength: 64
        automationVersionId:
          type: string
          minLength: 1
          maxLength: 64
        triggerInstanceId:
          type: string
          minLength: 4
          maxLength: 64
        mode:
          type: string
          enum:
            - live
            - test
        status:
          type: string
          enum:
            - pending
            - running
            - completed
            - failed
            - canceled
        recipientEmail:
          type: string
        startedAt:
          type: string
          format: date-time
        completedAt:
          type: string
          format: date-time
        error:
          type: string
      required:
        - automationRunId
        - automationId
        - mode
        - status
      additionalProperties: false
    AutomationRunLogRow:
      type: object
      properties:
        automationRunId:
          type: string
          minLength: 1
          maxLength: 64
        nodeId:
          type: string
          minLength: 1
        nodeName:
          type: string
          minLength: 1
        nodeType:
          type: string
          enum:
            - trigger
            - wait
            - filter
            - split
            - sendEmail
        status:
          type: string
          enum:
            - running
            - success
            - error
            - skipped
        orderIndex:
          type: integer
          minimum: 0
        branch:
          type: string
          minLength: 1
        durationMs:
          type: integer
          minimum: 0
        startedAt:
          type: string
          format: date-time
        completedAt:
          type: string
          format: date-time
        error:
          type: string
      required:
        - automationRunId
        - nodeId
        - nodeName
        - nodeType
        - status
        - orderIndex
        - startedAt
      additionalProperties: false
    TriggerRow:
      type: object
      properties:
        triggerEventId:
          type: string
          minLength: 1
          maxLength: 256
        title:
          type: string
          minLength: 1
          maxLength: 120
        description:
          type: string
          maxLength: 2000
        provider:
          type: string
          enum:
            - brew_api
            - clerk
            - stripe
            - shopify
            - stytch
            - supabase
            - workos
            - revenuecat
            - custom
        providerEventKey:
          type: string
        payloadSchema:
          type: object
          properties:
            type:
              type: string
              enum:
                - object
            fields:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    minLength: 1
                    description: Variable name used by emails and automations, e.g. email or firstName. Prefer self-descriptive keys; this column has no separate description field.
                  type:
                    type: string
                    enum:
                      - string
                      - int
                      - boolean
                  required:
                    type: boolean
                  fallbackValue:
                    anyOf:
                      - type: string
                      - type: number
                      - type: boolean
                    description: Substitution value when the inbound payload is missing this field. Also used as the email agent's `e.g. {{ key | fallback }}` example.
                  pii:
                    type: string
                    enum:
                      - none
                      - low
                      - high
                    description: PII classification for redaction. "high" auto-redacts the value in execution logs and the inbound log. "low" (default when omitted) preserves the value. "none" is an explicit marker that the field is non-personal.
                required:
                  - key
                  - type
                  - required
          required:
            - type
            - fields
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        skill:
          type: string
      required:
        - triggerEventId
        - title
        - provider
        - payloadSchema
        - createdAt
        - updatedAt
      additionalProperties: false
    TriggerEventInstance:
      type: object
      properties:
        triggerInstanceId:
          type: string
          minLength: 1
        source:
          type: string
          enum:
            - api
            - integration
        provider:
          type: string
        triggerEventId:
          type: string
          minLength: 1
          maxLength: 256
        state:
          type: string
          minLength: 1
        matchedAutomationIds:
          type: array
          items:
            type: string
        automationRunIds:
          type: array
          items:
            type: string
        rejectionReason:
          type: string
        attempts:
          type: integer
          minimum: 0
        receivedAt:
          type: string
          format: date-time
        processedAt:
          type: string
          format: date-time
      required:
        - triggerInstanceId
        - source
        - state
        - matchedAutomationIds
        - automationRunIds
        - attempts
        - receivedAt
      additionalProperties: false
    Contact:
      type: object
      properties:
        email:
          type: string
          format: email
        firstName:
          type: string
        lastName:
          type: string
        subscribed:
          type: boolean
          default: true
        validationStatus:
          type: string
          enum:
            - valid
            - risky
            - invalid
        verificationStatus:
          type: string
          enum:
            - valid
            - risky
            - invalid
          description: "Deprecated: legacy mirror of validationStatus. Will be removed; read validationStatus."
        suppressed:
          type: boolean
          default: false
        suppressedReason:
          type:
            - string
            - "null"
        lastValidatedAt:
          type: string
          format: date-time
        validationDetails:
          type: object
          properties:
            provider:
              type: string
              enum:
                - brew
            reason:
              type: string
            didYouMean:
              type: string
            risk:
              type: string
            isDisposable:
              type: boolean
            isRole:
              type: boolean
          required:
            - provider
          additionalProperties: false
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        importId:
          type:
            - string
            - "null"
        csvFileName:
          type:
            - string
            - "null"
        customFields:
          type: object
          additionalProperties: {}
          default: {}
      required:
        - email
        - createdAt
        - updatedAt
      additionalProperties: false
    ContactFieldDefinition:
      type: object
      properties:
        fieldName:
          type: string
          minLength: 1
        fieldType:
          type: string
          enum:
            - string
            - number
            - date
            - bool
        label:
          type: string
        isCore:
          type: boolean
        isFilterable:
          type: boolean
        isSortable:
          type: boolean
        isSearchable:
          type: boolean
        coverage:
          type: object
          properties:
            percent:
              type: integer
              minimum: 0
              maximum: 100
            approximate:
              type: boolean
            topValues:
              type: array
              items:
                type: object
                properties:
                  value:
                    type: string
                  count:
                    type: integer
                    minimum: 0
                  percent:
                    type: integer
                    minimum: 0
                    maximum: 100
                required:
                  - value
                  - count
                  - percent
                additionalProperties: false
            dominantValue:
              type: string
          required:
            - percent
            - approximate
            - topValues
          additionalProperties: false
      required:
        - fieldName
        - fieldType
      additionalProperties: false
    Audience:
      type: object
      properties:
        audienceId:
          type: string
          minLength: 1
          maxLength: 64
        audienceName:
          type: string
          minLength: 1
          maxLength: 200
        filters:
          type: object
          properties:
            filters:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    minLength: 1
                  operator:
                    type: string
                    enum:
                      - equals
                      - not_equals
                      - contains
                      - not_contains
                      - contains_any
                      - not_contains_any
                      - starts_with
                      - ends_with
                      - gt
                      - gte
                      - lt
                      - lte
                      - between
                      - is_true
                      - is_false
                      - in
                      - not_in
                      - is_empty
                      - not_exists
                      - is_not_empty
                      - exists
                      - is_set
                      - before
                      - after
                      - on_date
                  value: {}
                  type:
                    type: string
                    description: The field's value type — set `number`, `date`, or `boolean` for typed comparisons (dates are stored as epoch-ms, so a string `equals` on a date never matches). Omit for plain string fields.
                required:
                  - field
                  - operator
                additionalProperties: false
            logicalOperator:
              type: string
              enum:
                - and
                - or
          required:
            - filters
            - logicalOperator
          additionalProperties: false
        count:
          type: integer
          minimum: 0
        materializationStatus:
          type: string
          enum:
            - pending
            - running
            - ready
            - failed
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        build:
          type: object
          properties:
            jobId:
              type: string
              minLength: 1
              maxLength: 64
            status:
              type: string
              enum:
                - pending
                - running
                - completed
                - partial
                - failed
            cohort:
              type: object
              properties:
                eventTypes:
                  type: array
                  items:
                    type: string
                    enum:
                      - sent
                      - delivered
                      - delivery_delayed
                      - opened
                      - clicked
                      - bounced
                      - complained
                      - failed
                      - skipped
                      - unsubscribed
                  minItems: 1
                  maxItems: 10
                from:
                  type: string
                  format: date-time
                to:
                  type: string
                  format: date-time
                  description: Defaults to now.
                sendId:
                  type: string
                  minLength: 1
                  maxLength: 64
                emailId:
                  type: string
                  minLength: 1
                  maxLength: 64
                automationIds:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 64
                  maxItems: 20
                audienceIds:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 64
                  maxItems: 20
                  description: Scope to events from sends that targeted these audiences.
                recipient:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 320
                  maxItems: 10
                  description: Recipient rule tokens using the Events-page grammar.
                includeMachineClicks:
                  type: boolean
              required:
                - eventTypes
                - from
                - to
              additionalProperties: false
            field:
              type: object
              properties:
                key:
                  type: string
                  minLength: 1
                label:
                  type: string
                  minLength: 1
                type:
                  type: string
                  enum:
                    - date
              required:
                - key
                - label
                - type
              additionalProperties: false
            counts:
              type: object
              properties:
                eventsScanned:
                  type: integer
                  minimum: 0
                stampedContacts:
                  type: integer
                  minimum: 0
              required:
                - eventsScanned
              additionalProperties: false
            error:
              type: string
            enqueuedAt:
              type: string
              format: date-time
            completedAt:
              type: string
              format: date-time
          required:
            - jobId
            - status
            - cohort
            - field
            - counts
            - enqueuedAt
          additionalProperties: false
      required:
        - audienceId
        - audienceName
        - filters
        - count
        - createdAt
        - updatedAt
      additionalProperties: false
    AudienceBuild:
      type: object
      properties:
        jobId:
          type: string
          minLength: 1
          maxLength: 64
        status:
          type: string
          enum:
            - pending
            - running
            - completed
            - partial
            - failed
        cohort:
          type: object
          properties:
            eventTypes:
              type: array
              items:
                type: string
                enum:
                  - sent
                  - delivered
                  - delivery_delayed
                  - opened
                  - clicked
                  - bounced
                  - complained
                  - failed
                  - skipped
                  - unsubscribed
              minItems: 1
              maxItems: 10
            from:
              type: string
              format: date-time
            to:
              type: string
              format: date-time
              description: Defaults to now.
            sendId:
              type: string
              minLength: 1
              maxLength: 64
            emailId:
              type: string
              minLength: 1
              maxLength: 64
            automationIds:
              type: array
              items:
                type: string
                minLength: 1
                maxLength: 64
              maxItems: 20
            audienceIds:
              type: array
              items:
                type: string
                minLength: 1
                maxLength: 64
              maxItems: 20
              description: Scope to events from sends that targeted these audiences.
            recipient:
              type: array
              items:
                type: string
                minLength: 1
                maxLength: 320
              maxItems: 10
              description: Recipient rule tokens using the Events-page grammar.
            includeMachineClicks:
              type: boolean
          required:
            - eventTypes
            - from
            - to
          additionalProperties: false
        field:
          type: object
          properties:
            key:
              type: string
              minLength: 1
            label:
              type: string
              minLength: 1
            type:
              type: string
              enum:
                - date
          required:
            - key
            - label
            - type
          additionalProperties: false
        counts:
          type: object
          properties:
            eventsScanned:
              type: integer
              minimum: 0
            stampedContacts:
              type: integer
              minimum: 0
          required:
            - eventsScanned
          additionalProperties: false
        error:
          type: string
        enqueuedAt:
          type: string
          format: date-time
        completedAt:
          type: string
          format: date-time
      required:
        - jobId
        - status
        - cohort
        - field
        - counts
        - enqueuedAt
      additionalProperties: false
    Domain:
      type: object
      properties:
        domainId:
          type: string
          minLength: 1
          maxLength: 64
        domainUrl:
          type: string
          format: uri
        name:
          type: string
          minLength: 1
          maxLength: 253
        region:
          type: string
        status:
          type: string
          enum:
            - not_started
            - pending
            - verified
            - failed
            - temporary_failure
            - partially_verified
            - partially_failed
        sendingEnabled:
          type: boolean
        sendable:
          type: boolean
        sendingPurpose:
          type: string
          enum:
            - marketing
            - transactional
          description: marketing (default) or transactional. Transactional domains skip unsubscribe and may only send via API/MCP inline `to` (or a test send).
        records:
          type: array
          items:
            type: object
            properties:
              record:
                type: string
              name:
                type: string
              type:
                type: string
              ttl:
                type: string
              status:
                type: string
              value:
                type: string
              priority:
                type: number
            required:
              - record
              - name
              - type
              - ttl
              - status
              - value
            additionalProperties: false
        openTracking:
          type: boolean
        clickTracking:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        verifiedAt:
          type: string
          format: date-time
      required:
        - domainId
        - domainUrl
        - name
        - region
        - status
        - sendingEnabled
        - sendable
        - sendingPurpose
        - records
        - createdAt
        - updatedAt
      additionalProperties: false
    Template:
      type: object
      properties:
        emailId:
          type: string
          minLength: 1
        title:
          type: string
          minLength: 1
        category:
          type: string
          minLength: 1
        brand:
          type: string
          minLength: 1
        html:
          type: string
          minLength: 1
        previewImage:
          type: string
          format: uri
        updatedAt:
          type: string
          minLength: 1
      required:
        - emailId
        - title
        - html
        - previewImage
        - updatedAt
      additionalProperties: false
    EmailsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              emailId:
                type: string
                minLength: 1
              emailVersionId:
                type: string
                minLength: 1
              title:
                type: string
                minLength: 1
              status:
                type: string
                enum:
                  - streaming
                  - complete
                  - error
              previewImage:
                type: string
                format: uri
              updatedAt:
                type: string
                format: date-time
              subjectLine:
                type: string
                description: The design's default inbox subject, persisted on the latest version. Distinct from `title` (canvas name). Detail-only; absent on rows where it has never been set (via the write surfaces' `subjectLine` field, or in-app). `POST /v1/sends` still requires an explicit `subject`.
              previewText:
                type: string
                description: The design's inbox preview line, read directly from the latest version's JSX <Preview> (its single source of truth) — what a send delivers when no explicit `previewText` override is passed to POST /v1/sends. Detail-only; absent when the design has no <Preview>.
              html:
                type: string
              versions:
                type: array
                items:
                  type: object
                  properties:
                    version:
                      anyOf:
                        - type: integer
                          minimum: 0
                        - type: string
                          enum:
                            - latest
                    emailVersionId:
                      type: string
                      minLength: 1
                  required:
                    - version
                    - emailVersionId
                  additionalProperties: false
              group:
                type:
                  - object
                  - "null"
                properties:
                  groupId:
                    type: string
                    minLength: 1
                    maxLength: 64
                  groupName:
                    type: string
                    minLength: 1
                    maxLength: 60
                required:
                  - groupId
                  - groupName
                additionalProperties: false
            required:
              - emailId
              - title
              - status
              - updatedAt
              - group
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
      additionalProperties: false
    ApiErrorEnvelope:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              minLength: 1
            type:
              type: string
              enum:
                - authentication_error
                - authorization_error
                - invalid_request
                - not_found
                - not_implemented
                - conflict
                - rate_limit
                - payment_required
                - service_unavailable
                - internal_error
            message:
              type: string
              minLength: 1
            param:
              type: string
              minLength: 1
            suggestion:
              type: string
              minLength: 1
            docs:
              type: string
              format: uri
            retryAfter:
              type: integer
              minimum: 0
            details:
              type: object
              additionalProperties: {}
          required:
            - code
            - type
            - message
            - suggestion
            - docs
      required:
        - error
    EmailGenerateTextResponse:
      type: object
      properties:
        response:
          type: string
          minLength: 1
      required:
        - response
      additionalProperties: false
    EmailGenerateGeneratedResponse:
      type: object
      properties:
        emailId:
          type: string
          minLength: 1
        emailVersionId:
          type: string
          minLength: 1
        html:
          type: string
        previewImage:
          type: string
          format: uri
        group:
          type:
            - object
            - "null"
          properties:
            groupId:
              type: string
              minLength: 1
              maxLength: 64
            groupName:
              type: string
              minLength: 1
              maxLength: 60
          required:
            - groupId
            - groupName
          additionalProperties: false
        subjectLine:
          type: string
      required:
        - emailId
        - emailVersionId
        - html
        - group
      additionalProperties: false
    EmailGenerateRequest:
      type: object
      properties:
        prompt:
          type: string
          minLength: 1
          description: What the email is about — campaign goal, key content, offer, tone. The more specific (product names, dates, discount, audience), the better the design.
        contentUrls:
          type: array
          items:
            type: string
            format: uri
          maxItems: 8
          description: Up to 8 source URLs to build the email FROM — each is crawled and synthesized into one email (newsletters, recaps, product roundups).
        referenceEmailId:
          type: string
          description: An existing design (`emailId` from `list_email_designs`) to use as the style/layout reference for the new email.
        category:
          type: string
          enum:
            - welcome
            - newsletter
            - promotional
            - product-launch
            - product-update
            - cart-abandonment
            - event-invitation
            - event-reminder
            - feedback-request
            - re-engagement
            - referral
            - business
            - internal
            - general
          description: "Marketing email category that steers the design treatment (exemplars, hero recipe, personalization) — mirrors what the in-app agent infers per request. One of: welcome, newsletter, promotional, product-launch, product-update, cart-abandonment, event-invitation, event-reminder, feedback-request, re-engagement, referral, business, internal, general. Omit for a general treatment. Transactional emails (receipts, password resets, order confirmations) are sent via automations with a trigger, not this endpoint."
        subjectLine:
          type: string
          minLength: 1
          maxLength: 250
          description: Inbox subject line to set on the design (`subjectLine` — distinct from `title`, the canvas name). Sends still take an explicit per-send `subject`; this is the design's default, seeded into the send dialog and returned by `GET /v1/emails?emailId=`.
        targetGroupId:
          type: string
          minLength: 1
          maxLength: 64
          description: Existing canvas group id (`grp_…`), or `ungrouped`. Mutually exclusive with `targetGroupName`.
        targetGroupName:
          type: string
          minLength: 1
          maxLength: 60
          description: Resolve-or-create a group by this name. Mutually exclusive with `targetGroupId`.
      required:
        - prompt
      additionalProperties: false
    EmailImportResponse:
      type: object
      properties:
        emailId:
          type: string
          minLength: 1
        emailVersionId:
          type: string
          minLength: 1
        html:
          type: string
        previewImage:
          type: string
          format: uri
        group:
          type:
            - object
            - "null"
          properties:
            groupId:
              type: string
              minLength: 1
              maxLength: 64
            groupName:
              type: string
              minLength: 1
              maxLength: 60
          required:
            - groupId
            - groupName
          additionalProperties: false
        subjectLine:
          type: string
        assetReport:
          type: object
          properties:
            discovered:
              type: integer
              minimum: 0
            rehosted:
              type: integer
              minimum: 0
            retained:
              type: integer
              minimum: 0
            stripped:
              type: integer
              minimum: 0
            warnings:
              type: array
              items:
                type: object
                properties:
                  code:
                    type: string
                    enum:
                      - fetch_failed_retained
                      - non_image_resource_retained
                      - social_icon_substituted
                      - unsafe_url_stripped
                      - unsupported_resource_retained
                      - upload_failed_retained
                  location:
                    type: string
                    enum:
                      - background
                      - css-url
                      - data-src
                      - data-srcset
                      - preload
                      - src
                      - srcset
                      - stylesheet
                      - vml-src
                  host:
                    type: string
                required:
                  - code
                  - location
                additionalProperties: false
          required:
            - discovered
            - rehosted
            - retained
            - stripped
            - warnings
          additionalProperties: false
      required:
        - emailId
        - emailVersionId
        - html
        - group
        - assetReport
      additionalProperties: false
    EmailImportRequest:
      type: object
      properties:
        format:
          type: string
          enum:
            - html
            - mjml
            - jsx
        content:
          type: string
          minLength: 1
        title:
          type: string
          minLength: 1
          maxLength: 200
        subjectLine:
          type: string
          minLength: 1
          maxLength: 250
          description: Inbox subject line to set on the design (`subjectLine` — distinct from `title`, the canvas name). Sends still take an explicit per-send `subject`; this is the design's default, seeded into the send dialog and returned by `GET /v1/emails?emailId=`.
        baseUrl:
          type: string
          format: uri
        targetGroupId:
          type: string
          minLength: 1
          maxLength: 64
          description: Existing canvas group id (`grp_…`), or `ungrouped`. Mutually exclusive with `targetGroupName`.
        targetGroupName:
          type: string
          minLength: 1
          maxLength: 60
          description: Resolve-or-create a group by this name. Mutually exclusive with `targetGroupId`.
      required:
        - format
        - content
      additionalProperties: false
    FigmaToEmailResponse:
      type: object
      properties:
        emailId:
          type: string
          minLength: 1
        emailVersionId:
          type: string
          minLength: 1
        title:
          type: string
          minLength: 1
        format:
          type: string
          enum:
            - jsx
            - html
        content:
          type: string
          minLength: 1
        warningCount:
          type: integer
          minimum: 0
        exportedNodeCount:
          type: integer
          minimum: 0
        previewImage:
          type: string
          format: uri
        group:
          type:
            - object
            - "null"
          properties:
            groupId:
              type: string
              minLength: 1
              maxLength: 64
            groupName:
              type: string
              minLength: 1
              maxLength: 60
          required:
            - groupId
            - groupName
          additionalProperties: false
        subjectLine:
          type: string
      required:
        - emailId
        - emailVersionId
        - title
        - format
        - content
        - warningCount
        - exportedNodeCount
        - group
      additionalProperties: false
    FigmaToEmailRequest:
      type: object
      properties:
        figmaUrl:
          type: string
          minLength: 1
          maxLength: 2048
          format: uri
          description: A figma.com design, file, or prototype URL for a specific frame. The URL must include a node-id query parameter.
        title:
          type: string
          minLength: 1
          maxLength: 120
          description: Optional design title; defaults to the Figma frame name.
        targetGroupId:
          type: string
          minLength: 1
          maxLength: 64
          description: Existing canvas group id (`grp_…`), or `ungrouped`. Mutually exclusive with `targetGroupName`.
        targetGroupName:
          type: string
          minLength: 1
          maxLength: 60
          description: Resolve-or-create a group by this name. Mutually exclusive with `targetGroupId`.
        subjectLine:
          type: string
          minLength: 1
          maxLength: 250
          description: Inbox subject line to set on the design (`subjectLine` — distinct from `title`, the canvas name). Sends still take an explicit per-send `subject`; this is the design's default, seeded into the send dialog and returned by `GET /v1/emails?emailId=`.
        format:
          type: string
          enum:
            - jsx
            - html
          default: jsx
          description: "Source representation returned in `content`: React Email JSX by default, or rendered email-safe HTML."
      required:
        - figmaUrl
      additionalProperties: false
    EmailGenerateResponse:
      anyOf:
        - type: object
          properties:
            emailId:
              type: string
              minLength: 1
            emailVersionId:
              type: string
              minLength: 1
            html:
              type: string
            previewImage:
              type: string
              format: uri
            group:
              type:
                - object
                - "null"
              properties:
                groupId:
                  type: string
                  minLength: 1
                  maxLength: 64
                groupName:
                  type: string
                  minLength: 1
                  maxLength: 60
              required:
                - groupId
                - groupName
              additionalProperties: false
            subjectLine:
              type: string
          required:
            - emailId
            - emailVersionId
            - html
            - group
          additionalProperties: false
        - type: object
          properties:
            response:
              type: string
              minLength: 1
          required:
            - response
          additionalProperties: false
    EmailEditRequest:
      type: object
      properties:
        prompt:
          type: string
          minLength: 1
          description: The edit to make, in plain language — e.g. "swap the hero for the spring campaign image and tighten the CTA copy". Scoped edits beat full rewrites. Omit to only set `subjectLine` (at least one of the two is required).
        emailVersionId:
          type: string
          minLength: 1
          maxLength: 64
          description: 'Pin the edit to a specific source version (from `list_email_designs` `include: ["versions"]`). Omit to edit the current latest.'
        contentUrls:
          type: array
          items:
            type: string
            format: uri
          maxItems: 8
          description: Up to 8 URLs whose content grounds the edit (e.g. the product page the new section should describe).
        subjectLine:
          type: string
          minLength: 1
          maxLength: 250
          description: Inbox subject line to set on the design (`subjectLine` — distinct from `title`, the canvas name). Sends still take an explicit per-send `subject`; this is the design's default, seeded into the send dialog and returned by `GET /v1/emails?emailId=`.
      additionalProperties: false
    EmailsDeleteResponse:
      type: object
      properties:
        emailId:
          type: string
          minLength: 1
        deleted:
          type: boolean
        reason:
          type: string
          enum:
            - already_deleted
            - not_found
          description: "Present when `deleted` is false: `already_deleted` means this design was hard-deleted earlier (see `deletedAt`) — it is gone, do not retry; `not_found` means no design with this id exists on this brand."
        deletedAt:
          type: string
          description: 'ISO timestamp of the earlier hard-delete (present with `reason: "already_deleted"`).'
      required:
        - emailId
        - deleted
      additionalProperties: false
    EmailCloneRequest:
      type: object
      properties:
        emailVersionId:
          type: string
          minLength: 1
          maxLength: 64
          description: 'Exact source version to clone (from `list_email_designs` with `include: ["versions"]`). Omit to clone the current latest version.'
        targetGroupId:
          type: string
          minLength: 1
          maxLength: 64
          description: Existing canvas group id (`grp_…`), or `ungrouped`. Mutually exclusive with `targetGroupName`.
        targetGroupName:
          type: string
          minLength: 1
          maxLength: 60
          description: Resolve-or-create a group by this name. Mutually exclusive with `targetGroupId`.
      additionalProperties: false
    EmailRestoreRequest:
      type: object
      properties:
        version:
          type: integer
          minimum: 0
      required:
        - version
      additionalProperties: false
    EmailExportResponse:
      type: object
      properties:
        emailId:
          type: string
        provider:
          type: string
          enum:
            - braze
            - hubspot
            - klaviyo
            - mailchimp
            - iterable
            - postmark
            - onesignal
            - mailgun
            - sendgrid
        providerName:
          type: string
        templateName:
          type: string
        templateId:
          type: string
        dryRun:
          type: boolean
      required:
        - emailId
        - provider
        - providerName
        - templateName
        - dryRun
    EmailExportRequest:
      type: object
      properties:
        provider:
          type: string
          enum:
            - braze
            - hubspot
            - klaviyo
            - mailchimp
            - iterable
            - postmark
            - onesignal
            - mailgun
            - sendgrid
          description: The connected ESP to export the design to as a template.
        templateName:
          type: string
          minLength: 1
          maxLength: 100
          description: Template name in the ESP. Defaults to the email title.
        dryRun:
          type: boolean
          description: Validate the design, brand ownership, and ESP connection without creating a template.
        dry_run:
          type: boolean
          description: Accepted alias of `dryRun`.
      required:
        - provider
      additionalProperties: false
    EmailAccessibilityAuditResponse:
      type: object
      properties:
        score:
          type: integer
          minimum: 0
          maximum: 100
        summary:
          type: object
          properties:
            errors:
              type: integer
              minimum: 0
            warnings:
              type: integer
              minimum: 0
          required:
            - errors
            - warnings
          additionalProperties: false
        issues:
          type: array
          items:
            type: object
            properties:
              rule:
                type: string
              severity:
                type: string
                enum:
                  - error
                  - warning
              message:
                type: string
              wcag:
                type: string
              element:
                type: string
            required:
              - rule
              - severity
              - message
            additionalProperties: false
      required:
        - score
        - summary
        - issues
      additionalProperties: false
    EmailClientPreviewResponse:
      type: object
      properties:
        emailId:
          type: string
        status:
          type: string
          enum:
            - ready
            - partial
        previews:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              label:
                type: string
              category:
                type: string
                enum:
                  - gmail
                  - outlook
                  - apple
                  - yahoo
                  - other
              os:
                type: string
              dark:
                type: boolean
              status:
                type: string
                enum:
                  - ready
                  - processing
                  - failed
              imageUrl:
                type:
                  - string
                  - "null"
                format: uri
            required:
              - id
              - label
              - category
              - os
              - dark
              - status
              - imageUrl
            additionalProperties: false
        pending:
          type: array
          items:
            type: string
      required:
        - emailId
        - status
        - previews
        - pending
      additionalProperties: false
    EmailClientPreviewRequest:
      type: object
      properties:
        clients:
          type: array
          items:
            type: string
            minLength: 1
            maxLength: 80
          minItems: 1
          maxItems: 12
          description: "Client ids to render. Omit for a default popular spread of Gmail, Outlook, Apple Mail & iOS. Supported: gmailcom-lm_chrcurrent_win10 = Gmail (Web); gmailcom-dm_chrcurrent_win10 = Gmail (Web, Dark); android16_gmailapp_pixel10_lm = Gmail (Android); android16_gmailapp_pixel10_dm = Gmail (Android, Dark); iphone16gmail_18 = Gmail (iOS); outlook2021_win11_lm_dt = Outlook 2021 (Windows); outlook2021_win11_dm_dt = Outlook 2021 (Windows, Dark); o365_w10_lm_dt = Outlook 365 (Windows); outlookcom-lm_chrcurrent_win10 = Outlook.com (Web); applemail16 = Apple Mail (macOS); applemail16_dm = Apple Mail (macOS, Dark); iphone16_18 = Apple Mail (iOS); iphone16_18_dm = Apple Mail (iOS, Dark); yahoocom-lm_chrcurrent_win10 = Yahoo Mail (Web)."
      additionalProperties: false
    EmailInboxPlacementTest:
      type: object
      properties:
        testId:
          type: string
        emailId:
          type: string
        status:
          type: string
          enum:
            - pending
            - sending
            - collecting
            - completed
            - partial
            - failed
        domainId:
          type: string
        subject:
          type: string
        previewText:
          type: string
        emailVersionId:
          type: string
        seedCount:
          type: integer
          minimum: 0
        results:
          type:
            - object
            - "null"
          properties:
            overall:
              type: object
              properties:
                provider:
                  type: string
                total:
                  type: integer
                  minimum: 0
                inbox:
                  type: integer
                  minimum: 0
                spam:
                  type: integer
                  minimum: 0
                missing:
                  type: integer
                  minimum: 0
                pending:
                  type: integer
                  minimum: 0
                categories:
                  type: object
                  additionalProperties:
                    type: integer
                    minimum: 0
                folders:
                  type: object
                  additionalProperties:
                    type: integer
                    minimum: 0
                authentication:
                  type: object
                  properties:
                    spf:
                      type: string
                      enum:
                        - pass
                        - fail
                        - mixed
                    dkim:
                      type: string
                      enum:
                        - pass
                        - fail
                        - mixed
                    dmarc:
                      type: string
                      enum:
                        - pass
                        - fail
                        - mixed
                  additionalProperties: false
              required:
                - provider
                - total
                - inbox
                - spam
                - missing
                - pending
              additionalProperties: false
            byProvider:
              type: array
              items:
                type: object
                properties:
                  provider:
                    type: string
                  total:
                    type: integer
                    minimum: 0
                  inbox:
                    type: integer
                    minimum: 0
                  spam:
                    type: integer
                    minimum: 0
                  missing:
                    type: integer
                    minimum: 0
                  pending:
                    type: integer
                    minimum: 0
                  categories:
                    type: object
                    additionalProperties:
                      type: integer
                      minimum: 0
                  folders:
                    type: object
                    additionalProperties:
                      type: integer
                      minimum: 0
                  authentication:
                    type: object
                    properties:
                      spf:
                        type: string
                        enum:
                          - pass
                          - fail
                          - mixed
                      dkim:
                        type: string
                        enum:
                          - pass
                          - fail
                          - mixed
                      dmarc:
                        type: string
                        enum:
                          - pass
                          - fail
                          - mixed
                    additionalProperties: false
                required:
                  - provider
                  - total
                  - inbox
                  - spam
                  - missing
                  - pending
                additionalProperties: false
            authentication:
              type: object
              properties:
                spf:
                  type: string
                dkim:
                  type: string
                dmarc:
                  type: string
              additionalProperties: false
            spamFilter:
              type: object
              properties:
                flagged:
                  type: boolean
                score:
                  type: number
                threshold:
                  type: number
                rules:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                      score:
                        type: number
                      description:
                        type: string
                    required:
                      - name
                      - score
                    additionalProperties: false
              required:
                - flagged
                - score
                - threshold
                - rules
              additionalProperties: false
            microsoftFilter:
              type: object
              properties:
                spamConfidenceLevel:
                  type: number
                bulkComplaintLevel:
                  type: number
                sampleCount:
                  type: integer
                  minimum: 0
                junked:
                  type: boolean
              required:
                - spamConfidenceLevel
                - bulkComplaintLevel
                - sampleCount
                - junked
              additionalProperties: false
            spoofingDetected:
              type: boolean
            headers:
              type: object
              properties:
                listUnsubscribe:
                  type: boolean
                oneClickUnsubscribe:
                  type: boolean
                plainTextPart:
                  type: boolean
                feedbackId:
                  type: boolean
              required:
                - listUnsubscribe
                - oneClickUnsubscribe
                - plainTextPart
                - feedbackId
              additionalProperties: false
          required:
            - overall
            - byProvider
            - authentication
          additionalProperties: false
        diagnosis:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                enum:
                  - spoofing_detected
                  - aggregate_auth_failure
                  - provider_auth_failure
                  - microsoft_junk_filtering
                  - provider_spam_placement
                  - promotions_tab_placement
                  - bulk_folder_placement
                  - content_filter_flagged
                  - content_rule
                  - missing_list_unsubscribe
                  - missing_plain_text_part
              severity:
                type: string
                enum:
                  - critical
                  - warning
                  - info
              provider:
                type: string
              summary:
                type: string
              remediation:
                type: string
            required:
              - id
              - severity
              - summary
              - remediation
            additionalProperties: false
        errorMessage:
          type: string
        createdAt:
          type: string
        updatedAt:
          type: string
      required:
        - testId
        - emailId
        - status
        - domainId
        - seedCount
        - results
        - createdAt
        - updatedAt
      additionalProperties: false
    EmailInboxPlacementRequest:
      type: object
      properties:
        domainId:
          type: string
          minLength: 1
          maxLength: 64
          description: Verified sending domain id to test FROM (the seed send goes out on this domain, so the result reflects its real reputation).
        subject:
          type: string
          minLength: 1
          maxLength: 200
          description: Subject line for the seed send; defaults to the email title. A VARIANT dimension — run several tests on one design varying only the subject to compare placement.
        previewText:
          type: string
          maxLength: 200
          description: "Preview/preheader text for the seed send — overrides the design's JSX <Preview> for this test. A VARIANT dimension, like `subject`: run several tests varying only the preheader to compare placement."
        emailVersionId:
          type: string
          minLength: 1
          description: Pin a specific design version already available in the current surface; omit for the latest. A VARIANT dimension — test two versions of one design against each other.
        providers:
          type: array
          items:
            type: string
            minLength: 1
            maxLength: 80
          minItems: 1
          maxItems: 30
          description: Restrict seed mailbox providers (e.g. ["gmail.com","outlook.com","yahoo.com"]); omit for a broad default spread.
      required:
        - domainId
      additionalProperties: false
    EmailInboxPlacementGetResponse:
      anyOf:
        - $ref: "#/components/schemas/EmailInboxPlacementTest"
        - $ref: "#/components/schemas/EmailInboxPlacementTestList"
    EmailInboxPlacementTestList:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              testId:
                type: string
              status:
                type: string
                enum:
                  - pending
                  - sending
                  - collecting
                  - completed
                  - partial
                  - failed
              domainId:
                type: string
              subject:
                type: string
              previewText:
                type: string
              emailVersionId:
                type: string
              seedCount:
                type: integer
                minimum: 0
              overall:
                type:
                  - object
                  - "null"
                properties:
                  provider:
                    type: string
                  total:
                    type: integer
                    minimum: 0
                  inbox:
                    type: integer
                    minimum: 0
                  spam:
                    type: integer
                    minimum: 0
                  missing:
                    type: integer
                    minimum: 0
                  pending:
                    type: integer
                    minimum: 0
                  categories:
                    type: object
                    additionalProperties:
                      type: integer
                      minimum: 0
                  folders:
                    type: object
                    additionalProperties:
                      type: integer
                      minimum: 0
                  authentication:
                    type: object
                    properties:
                      spf:
                        type: string
                        enum:
                          - pass
                          - fail
                          - mixed
                      dkim:
                        type: string
                        enum:
                          - pass
                          - fail
                          - mixed
                      dmarc:
                        type: string
                        enum:
                          - pass
                          - fail
                          - mixed
                    additionalProperties: false
                required:
                  - provider
                  - total
                  - inbox
                  - spam
                  - missing
                  - pending
                additionalProperties: false
              createdAt:
                type: string
              updatedAt:
                type: string
            required:
              - testId
              - status
              - domainId
              - subject
              - seedCount
              - overall
              - createdAt
              - updatedAt
            additionalProperties: false
      required:
        - data
      additionalProperties: false
    EmailGroupsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              groupId:
                type: string
                minLength: 1
                maxLength: 64
              groupName:
                type: string
                minLength: 1
                maxLength: 60
              emailCount:
                type: integer
                minimum: 0
            required:
              - groupId
              - groupName
              - emailCount
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
      additionalProperties: false
    EmailGroupCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 60
          description: Named folder label (1–60 chars). Reserved names `Ungrouped` / `ungrouped` / `__ungrouped__` are rejected.
      required:
        - name
      additionalProperties: false
    EmailGroupPatchRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 60
          description: Named folder label (1–60 chars). Reserved names `Ungrouped` / `ungrouped` / `__ungrouped__` are rejected.
      required:
        - name
      additionalProperties: false
    EmailGroupDeleteResponse:
      type: object
      properties:
        groupId:
          type: string
          minLength: 1
          maxLength: 64
        deleted:
          type: boolean
      required:
        - groupId
        - deleted
      additionalProperties: false
    SendsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              sendId:
                type: string
                minLength: 1
              kind:
                type: string
                enum:
                  - campaign
                  - automation
                  - transactional
              messageClass:
                type: string
                enum:
                  - marketing
                  - transactional
              transactionId:
                type: string
                minLength: 1
              emailId:
                type: string
                minLength: 1
              emailVersionId:
                type: string
                minLength: 1
              status:
                type: string
                enum:
                  - scheduled
                  - queued
                  - sending
                  - paused
                  - sent
                  - partially_sent
                  - failed
                  - canceled
              approvalState:
                type: string
                enum:
                  - pending
                  - approved
                  - rejected
              subject:
                type: string
              previewText:
                type: string
              fromAddress:
                type: string
              senderName:
                type: string
              replyTo:
                type: string
              domainId:
                type: string
              audienceId:
                type: string
                minLength: 1
              audienceName:
                type: string
                minLength: 1
              recipientCount:
                type: integer
                minimum: 0
              runId:
                type: string
                minLength: 1
              scheduledAt:
                type: string
                format: date-time
              startedAt:
                type: string
                format: date-time
              completedAt:
                type: string
                format: date-time
              failedAt:
                type: string
                format: date-time
              error:
                type: string
              stats:
                type: object
                properties:
                  sent:
                    type: integer
                    minimum: 0
                  delivered:
                    type: integer
                    minimum: 0
                  opened:
                    type: integer
                    minimum: 0
                  clicked:
                    type: integer
                    minimum: 0
                  bounced:
                    type: integer
                    minimum: 0
                  complained:
                    type: integer
                    minimum: 0
                  unsubscribed:
                    type: integer
                    minimum: 0
                required:
                  - sent
                  - delivered
                  - opened
                  - clicked
                  - bounced
                  - complained
                  - unsubscribed
                additionalProperties: false
              delivery:
                type: object
                properties:
                  accepted:
                    type: integer
                    minimum: 0
                  pending:
                    type: integer
                    minimum: 0
                  delayed:
                    type: integer
                    minimum: 0
                  delivered:
                    type: integer
                    minimum: 0
                  bounced:
                    type: integer
                    minimum: 0
                  failed:
                    type: integer
                    minimum: 0
                  providerSuppressed:
                    type: integer
                    minimum: 0
                  preSendSkipped:
                    type: integer
                    minimum: 0
                  renderFailed:
                    type: integer
                    minimum: 0
                  updatedAt:
                    type: string
                    format: date-time
                required:
                  - accepted
                  - pending
                  - delayed
                  - delivered
                  - bounced
                  - failed
                  - providerSuppressed
                  - preSendSkipped
                  - renderFailed
                  - updatedAt
                additionalProperties: false
              gradualSend:
                type: object
                properties:
                  startingPercentage:
                    type: number
                    minimum: 0.1
                    maximum: 100
                  incrementPercentage:
                    type: number
                    minimum: 0
                    maximum: 100
                  interval:
                    oneOf:
                      - type: object
                        properties:
                          value:
                            type: integer
                            minimum: 1
                            maximum: 24
                          unit:
                            type: string
                            enum:
                              - hour
                        required:
                          - value
                          - unit
                        additionalProperties: false
                      - type: object
                        properties:
                          value:
                            type: integer
                            minimum: 1
                            maximum: 30
                          unit:
                            type: string
                            enum:
                              - day
                        required:
                          - value
                          - unit
                        additionalProperties: false
                  timeZone:
                    type: string
                    minLength: 1
                    description: IANA timezone used to preserve local wall-clock time for day intervals.
                  rampEndsAt:
                    type: string
                    format: date-time
                  currentTranche:
                    type: integer
                    exclusiveMinimum: 0
                  sentSoFar:
                    type: integer
                    minimum: 0
                  pausedAt:
                    type: string
                    format: date-time
                  pauseReason:
                    type: string
                    enum:
                      - manual
                  resumedAt:
                    type: string
                    format: date-time
                required:
                  - startingPercentage
                  - incrementPercentage
                  - interval
                  - timeZone
                additionalProperties: false
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time
              events:
                type: array
                items:
                  type: object
                  properties:
                    eventType:
                      type: string
                      enum:
                        - sent
                        - delivered
                        - delivery_delayed
                        - opened
                        - clicked
                        - bounced
                        - complained
                        - failed
                        - provider_suppressed
                        - suppressed
                        - quota_skipped
                        - received
                        - unsubscribed
                    occurredAt:
                      type: string
                      format: date-time
                    recipientEmail:
                      type: string
                    url:
                      type: string
                    machineGenerated:
                      type: boolean
                    clickBotReason:
                      type: string
                  required:
                    - eventType
                    - occurredAt
                  additionalProperties: false
            required:
              - sendId
              - kind
              - emailId
              - status
              - createdAt
              - updatedAt
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
      additionalProperties: false
    SendEmailTestResponse:
      type: object
      properties:
        status:
          type: string
          enum:
            - sent
        recipient:
          type: string
          format: email
      required:
        - status
        - recipient
      additionalProperties: false
    SendsPostResponse:
      anyOf:
        - type: object
          properties:
            status:
              type: string
              enum:
                - queued
                - scheduled
            sendId:
              type: string
              minLength: 1
            runId:
              type: string
              minLength: 1
            scheduledAt:
              type: string
              format: date-time
          required:
            - status
            - sendId
            - runId
          additionalProperties: false
        - type: object
          properties:
            status:
              type: string
              enum:
                - pending_approval
            sendId:
              type: string
              minLength: 1
            scheduledAt:
              type: string
              format: date-time
          required:
            - status
            - sendId
          additionalProperties: false
    SendEmailRequest:
      anyOf:
        - type: object
          properties:
            test:
              type: boolean
              enum:
                - true
            emailId:
              type: string
              minLength: 1
            emailVersionId:
              type: string
              minLength: 1
            subject:
              type: string
              minLength: 1
            previewText:
              type: string
              maxLength: 200
              description: Inbox preheader for this test send — overrides the design's JSX <Preview>. Omit to deliver the design's own preview line.
            to:
              type: string
              format: email
            replyTo:
              type: string
              format: email
            domainId:
              type: string
              minLength: 1
              description: OPTIONAL verified sending domain for this test. Omit for the Brew default sender (hello@email.brew.new). Must be a verified domain owned by this org/brand — an unverified or foreign domain is rejected (404/422), never silently downgraded to the Brew default.
            senderName:
              type: string
              minLength: 1
              maxLength: 128
            fromEmail:
              type: string
              minLength: 1
              maxLength: 64
            variables:
              type: object
              additionalProperties:
                type: string
                maxLength: 256
              description: Example values for {{ var | fallback }} merge tags in the subject, previewText, and body. A supplied value wins over contact fields and the declared fallback; undefined variables render their fallback (or empty). Max 25 entries; keys must match the merge-tag grammar (letter/_/$ start, then word chars/dots/$, max 64 chars); values max 256 chars.
            payload:
              type: object
              additionalProperties:
                $ref: "#/components/schemas/TransactionalPayloadValue"
              description: "Nested JSON template data for Liquid-mode designs, exposed as trigger.* / payload.*. Flat `variables` still resolve legacy {{ tag | fallback }} merge tags; send both if a design mixes syntaxes. Live-fire parity on non-Liquid workspaces: scalar keys resolve merge tags (below `variables`) and nested values are rejected with a 400."
          required:
            - test
            - emailId
            - subject
            - to
          additionalProperties: false
        - type: object
          properties:
            transactionId:
              type: string
              minLength: 1
              maxLength: 128
            to:
              anyOf:
                - type: string
                  format: email
                - type: array
                  items:
                    type: string
                    format: email
                  minItems: 1
                  maxItems: 50
              description: Recipient addresses (max 50). Required.
            payload:
              type: object
              additionalProperties:
                $ref: "#/components/schemas/TransactionalPayloadValue"
              description: "Template data for this fire. Flat scalar keys resolve legacy {{ tag | fallback }} merge tags; the full (optionally nested) JSON is exposed to Liquid templates as trigger.* / payload.*. Extra keys are ignored; missing keys use design fallbacks (or fail the send when the design opts into strict templating). Caps: 64 KiB serialized, 10 nesting levels, 250 items per array, 100 top-level keys."
            strict:
              type: boolean
              description: "Liquid strictness override for this fire: true fails the send on any unresolved template variable (customer.io parity) instead of rendering blank. Defaults to the transactional object setting. Ignored for legacy-engine orgs."
            replyTo:
              type: string
              description: Reply-to address. Accepts a bare email (`a@b.com`) or the display-name form (`Name <a@b.com>`).
            senderName:
              type: string
              minLength: 1
              maxLength: 128
            fromEmail:
              type: string
              minLength: 1
              maxLength: 64
            subject:
              type: string
              minLength: 1
            previewText:
              type: string
              maxLength: 200
          required:
            - transactionId
            - to
          additionalProperties: false
        - type: object
          properties:
            test:
              type: boolean
              enum:
                - false
            emailId:
              type: string
              minLength: 1
            emailVersionId:
              type: string
              minLength: 1
            subject:
              type: string
              minLength: 1
            previewText:
              type: string
              maxLength: 200
              description: Inbox preheader for THIS send — overrides the design's JSX <Preview>. Omit to deliver the design's own preview line (returned as `previewText` on `GET /v1/emails?emailId=`).
            replyTo:
              type: string
              description: Reply-to address. Accepts a bare email (`a@b.com`) or the display-name form (`Name <a@b.com>`).
            senderName:
              type: string
              minLength: 1
              maxLength: 128
            fromEmail:
              type: string
              minLength: 1
              maxLength: 64
            messageClass:
              type: string
              enum:
                - marketing
                - transactional
            consent:
              type: object
              properties:
                source:
                  type: string
                  enum:
                    - api
                    - form
                    - import
                capturedAt:
                  type: string
                  format: date-time
                policyVersion:
                  type: string
                  minLength: 1
                  maxLength: 64
              required:
                - source
                - capturedAt
                - policyVersion
              additionalProperties: false
            domainId:
              type: string
              minLength: 1
            audienceId:
              type: string
              minLength: 1
              description: A saved audience id, or "all" to target EVERY contact in the brand.
            to:
              anyOf:
                - type: string
                  format: email
                - type: array
                  items:
                    type: string
                    format: email
                  minItems: 1
                  maxItems: 50
              description: Inline recipient addresses (max 50). Mutually exclusive with `audienceId`.
            scheduledAt:
              type: string
              format: date-time
            gradualSend:
              type: object
              properties:
                startingPercentage:
                  type: number
                  minimum: 0.1
                  maximum: 100
                incrementPercentage:
                  type: number
                  minimum: 0
                  maximum: 100
                interval:
                  oneOf:
                    - type: object
                      properties:
                        value:
                          type: integer
                          minimum: 1
                          maximum: 24
                        unit:
                          type: string
                          enum:
                            - hour
                      required:
                        - value
                        - unit
                      additionalProperties: false
                    - type: object
                      properties:
                        value:
                          type: integer
                          minimum: 1
                          maximum: 30
                        unit:
                          type: string
                          enum:
                            - day
                      required:
                        - value
                        - unit
                      additionalProperties: false
                timeZone:
                  type: string
                  minLength: 1
                  description: IANA timezone used to preserve local wall-clock time for day intervals.
              required:
                - startingPercentage
                - incrementPercentage
                - interval
                - timeZone
              additionalProperties: false
          required:
            - emailId
            - subject
            - domainId
          additionalProperties: false
    SendCancelResponse:
      type: object
      properties:
        sendId:
          type: string
          minLength: 1
        status:
          type: string
          enum:
            - canceled
      required:
        - sendId
        - status
      additionalProperties: false
    SendPauseResponse:
      type: object
      properties:
        sendId:
          type: string
          minLength: 1
        status:
          type: string
          enum:
            - paused
      required:
        - sendId
        - status
      additionalProperties: false
    SendResumeResponse:
      type: object
      properties:
        sendId:
          type: string
          minLength: 1
        status:
          type: string
          enum:
            - sending
      required:
        - sendId
        - status
      additionalProperties: false
    AnalyticsOverviewResponse:
      type: object
      properties:
        totals:
          type: object
          properties:
            accepted:
              type: integer
              minimum: 0
              default: 0
            sent:
              type: integer
              minimum: 0
            delivered:
              type: integer
              minimum: 0
            opened:
              type: integer
              minimum: 0
            clicked:
              type: integer
              minimum: 0
            bounced:
              type: integer
              minimum: 0
            complained:
              type: integer
              minimum: 0
            unsubscribed:
              type: integer
              minimum: 0
            failed:
              type: integer
              minimum: 0
            providerSuppressed:
              type: integer
              minimum: 0
              default: 0
            suppressed:
              type: integer
              minimum: 0
            quotaSkipped:
              type: integer
              minimum: 0
              default: 0
            preSendSkipped:
              type: integer
              minimum: 0
              default: 0
            pending:
              type: integer
              minimum: 0
              default: 0
            deliveryDelayed:
              type: integer
              minimum: 0
          required:
            - sent
            - delivered
            - opened
            - clicked
            - bounced
            - complained
            - unsubscribed
            - failed
            - suppressed
            - deliveryDelayed
          additionalProperties: false
        rates:
          type: object
          properties:
            deliveryRate:
              type:
                - number
                - "null"
            openRate:
              type:
                - number
                - "null"
            clickRate:
              type:
                - number
                - "null"
            bounceRate:
              type:
                - number
                - "null"
            complaintRate:
              type:
                - number
                - "null"
            unsubscribeRate:
              type:
                - number
                - "null"
          required:
            - deliveryRate
            - openRate
            - clickRate
            - bounceRate
            - complaintRate
            - unsubscribeRate
          additionalProperties: false
        buckets:
          type: array
          items:
            type: object
            properties:
              at:
                type: string
                format: date-time
              sent:
                type: integer
                minimum: 0
              delivered:
                type: integer
                minimum: 0
              deliveryDelayed:
                type: integer
                minimum: 0
              opened:
                type: integer
                minimum: 0
              clicked:
                type: integer
                minimum: 0
              bounced:
                type: integer
                minimum: 0
              complained:
                type: integer
                minimum: 0
              failed:
                type: integer
                minimum: 0
              providerSuppressed:
                type: integer
                minimum: 0
                default: 0
              suppressed:
                type: integer
                minimum: 0
              quotaSkipped:
                type: integer
                minimum: 0
                default: 0
              unsubscribed:
                type: integer
                minimum: 0
            required:
              - at
              - sent
              - delivered
              - deliveryDelayed
              - opened
              - clicked
              - bounced
              - complained
              - failed
              - suppressed
              - unsubscribed
            additionalProperties: false
        granularity:
          type: string
          enum:
            - 5m
            - 1h
            - 1d
        timeZone:
          type: string
        range:
          type: object
          properties:
            from:
              type: string
              format: date-time
            to:
              type: string
              format: date-time
          required:
            - from
            - to
          additionalProperties: false
        truncated:
          type: boolean
      required:
        - totals
        - rates
        - buckets
        - granularity
        - timeZone
        - range
        - truncated
      additionalProperties: false
    CampaignAnalyticsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              sendId:
                type: string
                minLength: 1
              emailId:
                type: string
                minLength: 1
              title:
                type: string
              status:
                type: string
                enum:
                  - scheduled
                  - queued
                  - sending
                  - paused
                  - sent
                  - partially_sent
                  - failed
                  - canceled
              audienceName:
                type: string
              sentAt:
                type: string
                format: date-time
              stats:
                type: object
                properties:
                  accepted:
                    type: integer
                    minimum: 0
                    default: 0
                  sent:
                    type: integer
                    minimum: 0
                  delivered:
                    type: integer
                    minimum: 0
                  opened:
                    type: integer
                    minimum: 0
                  clicked:
                    type: integer
                    minimum: 0
                  bounced:
                    type: integer
                    minimum: 0
                  complained:
                    type: integer
                    minimum: 0
                  unsubscribed:
                    type: integer
                    minimum: 0
                required:
                  - sent
                  - delivered
                  - opened
                  - clicked
                  - bounced
                  - complained
                  - unsubscribed
                additionalProperties: false
            required:
              - sendId
              - emailId
              - title
              - status
              - stats
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
        - pagination
      additionalProperties: false
    AutomationAnalyticsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              automationId:
                type: string
                minLength: 1
              name:
                type: string
              published:
                type: boolean
              triggerEventId:
                type: string
              runs:
                type: integer
                minimum: 0
              completed:
                type: integer
                minimum: 0
              failed:
                type: integer
                minimum: 0
              sent:
                type: integer
                minimum: 0
              delivered:
                type: integer
                minimum: 0
              opened:
                type: integer
                minimum: 0
              clicked:
                type: integer
                minimum: 0
              bounced:
                type: integer
                minimum: 0
              complained:
                type: integer
                minimum: 0
              unsubscribed:
                type: integer
                minimum: 0
              successRate:
                type:
                  - number
                  - "null"
              openRate:
                type:
                  - number
                  - "null"
              clickRate:
                type:
                  - number
                  - "null"
              clickThroughRate:
                type:
                  - number
                  - "null"
              unsubscribeRate:
                type:
                  - number
                  - "null"
              lastRunAt:
                type: string
                format: date-time
              lastRunStatus:
                type: string
            required:
              - automationId
              - name
              - published
              - runs
              - completed
              - failed
              - sent
              - delivered
              - opened
              - clicked
              - bounced
              - complained
              - unsubscribed
              - successRate
              - openRate
              - clickRate
              - clickThroughRate
              - unsubscribeRate
            additionalProperties: false
        totals:
          type: object
          properties:
            runs:
              type: integer
              minimum: 0
            completed:
              type: integer
              minimum: 0
            failed:
              type: integer
              minimum: 0
            sent:
              type: integer
              minimum: 0
            delivered:
              type: integer
              minimum: 0
            opened:
              type: integer
              minimum: 0
            clicked:
              type: integer
              minimum: 0
            bounced:
              type: integer
              minimum: 0
            complained:
              type: integer
              minimum: 0
            unsubscribed:
              type: integer
              minimum: 0
          required:
            - runs
            - completed
            - failed
            - sent
            - delivered
            - opened
            - clicked
            - bounced
            - complained
            - unsubscribed
          additionalProperties: false
        range:
          type: object
          properties:
            from:
              type: string
              format: date-time
            to:
              type: string
              format: date-time
          required:
            - from
            - to
          additionalProperties: false
        truncated:
          type: boolean
      required:
        - data
        - totals
        - range
        - truncated
      additionalProperties: false
    EventsAnalyticsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                minLength: 1
              occurredAt:
                type: string
                format: date-time
              domain:
                type: string
                enum:
                  - email
                  - automation
                  - trigger
                  - inbound
              eventType:
                type: string
                minLength: 1
              recipientEmail:
                type: string
              sendId:
                type: string
              emailId:
                type: string
              emailName:
                type: string
              automationId:
                type: string
              automationName:
                type: string
              nodeId:
                type: string
              triggerEventId:
                type: string
              provider:
                type: string
              machineGenerated:
                type: boolean
              clickBotReason:
                type: string
              openBotReason:
                type: string
              openFetchSource:
                type: string
              mode:
                type: string
                enum:
                  - live
                  - test
              summary:
                type: string
              sendSource:
                type: string
                enum:
                  - audience
                  - api
                  - automation_manual
                  - automation_integration
                  - automation_custom
              messageClass:
                type: string
                enum:
                  - marketing
                  - transactional
              transactionId:
                type: string
              sendContext:
                type: string
              triggerProvider:
                type: string
              triggerTitle:
                type: string
            required:
              - id
              - occurredAt
              - domain
              - eventType
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
        range:
          type: object
          properties:
            from:
              type: string
              format: date-time
            to:
              type: string
              format: date-time
          required:
            - from
            - to
          additionalProperties: false
      required:
        - data
        - pagination
        - range
      additionalProperties: false
    AutomationsPostRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 120
        description:
          type: string
          maxLength: 2000
        triggerEventId:
          type: string
          minLength: 1
          maxLength: 256
        nodes:
          type: array
          items:
            oneOf:
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - trigger
                  config:
                    anyOf:
                      - type: object
                        properties:
                          actionType:
                            type: string
                          eventName:
                            type: string
                          mode:
                            type: string
                            enum:
                              - event
                          triggerEventId:
                            type: string
                        additionalProperties: false
                      - type: object
                        properties:
                          actionType:
                            type: string
                          eventName:
                            type: string
                          mode:
                            type: string
                            enum:
                              - manualAudience
                          audienceId:
                            type: string
                        required:
                          - mode
                          - audienceId
                        additionalProperties: false
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - sendEmail
                  config:
                    type: object
                    properties:
                      actionType:
                        type: string
                        description: Informational duplicate of node.type; ignored.
                      emailId:
                        type: string
                        minLength: 1
                        description: Email design id — required for sendEmail.
                      emailVersionId:
                        type: string
                        minLength: 1
                        description: Exact email version id for deterministic delivery — required.
                      domainId:
                        type: string
                        minLength: 1
                        description: Owned, verified sending-domain id — optional at authoring; required at publish / live run.
                      subject:
                        type: string
                        minLength: 1
                        description: Inbox subject — required. Supports {{var | fallback}} interpolation.
                      previewText:
                        type: string
                        description: Inbox preheader — optional; the email design's <Preview> is the source of truth and wins when present.
                      messageClass:
                        type: string
                        enum:
                          - marketing
                          - transactional
                        description: Leftover snapshot; ignored at delivery — the class comes from the sending domain’s purpose (automations always send marketing-class mail).
                      fromName:
                        type: string
                        minLength: 1
                        description: Sender display name; resolved from the domain default when unset.
                      replyTo:
                        type: string
                        format: email
                        description: Reply-to address; resolved from the domain default when unset.
                      emailTitle:
                        type: string
                        description: Informational email title mirror; tolerated for round-trips.
                      fromAddress:
                        type: string
                        description: Sender address on a verified sending domain; resolved from the domain default when unset.
                    required:
                      - emailId
                      - emailVersionId
                      - subject
                    additionalProperties: false
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - wait
                  config:
                    type: object
                    properties:
                      actionType:
                        type: string
                      duration:
                        type: number
                      unit:
                        type: string
                        enum:
                          - ms
                          - seconds
                          - minutes
                          - hours
                          - days
                          - weeks
                    required:
                      - duration
                      - unit
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - filter
                  config:
                    anyOf:
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - payload
                          logicalOperator:
                            type: string
                            enum:
                              - AND
                              - OR
                          conditions:
                            type: array
                            items:
                              anyOf:
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - contains
                                        - not_contains
                                        - starts_with
                                        - ends_with
                                    value:
                                      type: string
                                      description: String value to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - gt
                                        - gte
                                        - lt
                                        - lte
                                    value:
                                      type: number
                                      description: Finite numeric value to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - gt
                                        - gte
                                        - lt
                                        - lte
                                    value:
                                      anyOf:
                                        - type: string
                                          minLength: 1
                                        - type: number
                                      description: ISO date string or Unix timestamp in milliseconds to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - in
                                        - not_in
                                        - contains_any
                                        - not_contains_any
                                    value:
                                      type: array
                                      items:
                                        type: string
                                        minLength: 1
                                      minItems: 1
                                      description: Non-empty array of string values to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - in
                                        - not_in
                                    value:
                                      type: array
                                      items:
                                        type: number
                                      minItems: 1
                                      description: Non-empty array of finite numbers to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - between
                                    value:
                                      type: array
                                      prefixItems:
                                        - type: number
                                        - type: number
                                      description: Inclusive [minimum, maximum] numeric bounds.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - between
                                    value:
                                      type: array
                                      prefixItems:
                                        - anyOf:
                                            - type: string
                                              minLength: 1
                                            - type: number
                                        - anyOf:
                                            - type: string
                                              minLength: 1
                                            - type: number
                                      description: Inclusive [start, end] ISO-date or Unix-millisecond timestamp bounds.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - bool
                                    operator:
                                      type: string
                                      enum:
                                        - is_true
                                        - is_false
                                      description: Unary boolean check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                            minItems: 1
                        required:
                          - logicalOperator
                          - conditions
                        additionalProperties: false
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - engagement
                          sourceNodeId:
                            type: string
                            minLength: 1
                            description: Id of the upstream sendEmail node this filter watches for opens/clicks.
                          window:
                            type: object
                            properties:
                              duration:
                                type: number
                                minimum: 0
                              unit:
                                type: string
                                enum:
                                  - ms
                                  - seconds
                                  - minutes
                                  - hours
                                  - days
                                  - weeks
                            required:
                              - duration
                              - unit
                            additionalProperties: false
                          branches:
                            type: array
                            items:
                              type: object
                              properties:
                                id:
                                  type: string
                                label:
                                  type: string
                                condition:
                                  type: object
                                  properties:
                                    kind:
                                      type: string
                                      enum:
                                        - engaged
                                        - not_engaged
                                        - clicked_link
                                    events:
                                      type: string
                                      enum:
                                        - opened
                                        - clicked
                                        - opened_or_clicked
                                    url:
                                      type: string
                                    position:
                                      type: string
                                      enum:
                                        - any
                                        - first
                                        - last
                                  required:
                                    - kind
                              required:
                                - id
                                - condition
                            minItems: 1
                        required:
                          - mode
                          - sourceNodeId
                          - window
                          - branches
                        additionalProperties: false
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - split
                  config:
                    oneOf:
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - percentage
                          leftLabel:
                            type: string
                          rightLabel:
                            type: string
                          leftPercentage:
                            type: number
                            minimum: 0
                            maximum: 100
                          seed:
                            type: string
                        required:
                          - mode
                          - leftLabel
                          - rightLabel
                          - leftPercentage
                        additionalProperties: false
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - condition
                          leftLabel:
                            type: string
                          rightLabel:
                            type: string
                          logicalOperator:
                            type: string
                            enum:
                              - AND
                              - OR
                          conditions:
                            type: array
                            items:
                              anyOf:
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - contains
                                        - not_contains
                                        - starts_with
                                        - ends_with
                                    value:
                                      type: string
                                      description: String value to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - gt
                                        - gte
                                        - lt
                                        - lte
                                    value:
                                      type: number
                                      description: Finite numeric value to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - gt
                                        - gte
                                        - lt
                                        - lte
                                    value:
                                      anyOf:
                                        - type: string
                                          minLength: 1
                                        - type: number
                                      description: ISO date string or Unix timestamp in milliseconds to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - in
                                        - not_in
                                        - contains_any
                                        - not_contains_any
                                    value:
                                      type: array
                                      items:
                                        type: string
                                        minLength: 1
                                      minItems: 1
                                      description: Non-empty array of string values to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - in
                                        - not_in
                                    value:
                                      type: array
                                      items:
                                        type: number
                                      minItems: 1
                                      description: Non-empty array of finite numbers to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - between
                                    value:
                                      type: array
                                      prefixItems:
                                        - type: number
                                        - type: number
                                      description: Inclusive [minimum, maximum] numeric bounds.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - between
                                    value:
                                      type: array
                                      prefixItems:
                                        - anyOf:
                                            - type: string
                                              minLength: 1
                                            - type: number
                                        - anyOf:
                                            - type: string
                                              minLength: 1
                                            - type: number
                                      description: Inclusive [start, end] ISO-date or Unix-millisecond timestamp bounds.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - bool
                                    operator:
                                      type: string
                                      enum:
                                        - is_true
                                        - is_false
                                      description: Unary boolean check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                            minItems: 1
                        required:
                          - mode
                          - leftLabel
                          - rightLabel
                          - logicalOperator
                          - conditions
                        additionalProperties: false
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
          maxItems: 500
        connections:
          type: array
          items:
            type: object
            properties:
              from:
                type: string
                minLength: 1
              to:
                type: string
                minLength: 1
              branch:
                type: string
                minLength: 1
            required:
              - from
              - to
            additionalProperties: false
          maxItems: 1000
          default: []
        dryRun:
          type: boolean
          description: Validate only — runs the full publish-gate check and returns blockers/warnings without creating anything.
        dry_run:
          type: boolean
          description: Accepted alias of `dryRun`.
      required:
        - name
        - nodes
      additionalProperties: false
    AutomationsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              automationId:
                type: string
                minLength: 1
                maxLength: 64
              automationVersionId:
                type: string
                minLength: 1
                maxLength: 64
              triggerEventId:
                type: string
                minLength: 1
                maxLength: 256
              name:
                type: string
                minLength: 1
                maxLength: 120
              description:
                type: string
                maxLength: 2000
              version:
                anyOf:
                  - type: integer
                    minimum: 0
                  - type: string
                    enum:
                      - latest
              published:
                type: boolean
              isLive:
                type: boolean
              liveVersion:
                anyOf:
                  - type: integer
                    minimum: 0
                  - type: string
                    enum:
                      - latest
              liveAutomationVersionId:
                type: string
                minLength: 1
                maxLength: 64
              warnings:
                type: array
                items:
                  type: object
                  properties:
                    code:
                      type: string
                    message:
                      type: string
                  required:
                    - code
                    - message
                  additionalProperties: false
              paused:
                type: boolean
              pausedAt:
                type: number
              nodes:
                type: array
                items:
                  oneOf:
                    - type: object
                      properties:
                        id:
                          type: string
                          minLength: 1
                        label:
                          type: string
                          minLength: 1
                        description:
                          type: string
                        type:
                          type: string
                          enum:
                            - trigger
                        config:
                          anyOf:
                            - type: object
                              properties:
                                actionType:
                                  type: string
                                eventName:
                                  type: string
                                mode:
                                  type: string
                                  enum:
                                    - event
                                triggerEventId:
                                  type: string
                              additionalProperties: false
                            - type: object
                              properties:
                                actionType:
                                  type: string
                                eventName:
                                  type: string
                                mode:
                                  type: string
                                  enum:
                                    - manualAudience
                                audienceId:
                                  type: string
                              required:
                                - mode
                                - audienceId
                              additionalProperties: false
                      required:
                        - id
                        - label
                        - type
                        - config
                    - type: object
                      properties:
                        id:
                          type: string
                          minLength: 1
                        label:
                          type: string
                          minLength: 1
                        description:
                          type: string
                        type:
                          type: string
                          enum:
                            - sendEmail
                        config:
                          type: object
                          properties:
                            actionType:
                              type: string
                            emailId:
                              type: string
                            emailVersionId:
                              type: string
                            emailTitle:
                              type: string
                            subject:
                              type: string
                            previewText:
                              type: string
                            messageClass:
                              type: string
                              enum:
                                - marketing
                                - transactional
                            fromName:
                              type: string
                            fromAddress:
                              type: string
                            domainId:
                              type: string
                            replyTo:
                              type: string
                            to: {}
                            html:
                              type: string
                            variables:
                              type: object
                              additionalProperties: {}
                      required:
                        - id
                        - label
                        - type
                        - config
                    - type: object
                      properties:
                        id:
                          type: string
                          minLength: 1
                        label:
                          type: string
                          minLength: 1
                        description:
                          type: string
                        type:
                          type: string
                          enum:
                            - wait
                        config:
                          type: object
                          properties:
                            actionType:
                              type: string
                            duration:
                              type: number
                            unit:
                              type: string
                              enum:
                                - ms
                                - seconds
                                - minutes
                                - hours
                                - days
                                - weeks
                          required:
                            - duration
                            - unit
                      required:
                        - id
                        - label
                        - type
                        - config
                    - type: object
                      properties:
                        id:
                          type: string
                          minLength: 1
                        label:
                          type: string
                          minLength: 1
                        description:
                          type: string
                        type:
                          type: string
                          enum:
                            - filter
                        config:
                          anyOf:
                            - type: object
                              properties:
                                actionType:
                                  type: string
                                mode:
                                  type: string
                                  enum:
                                    - payload
                                logicalOperator:
                                  type: string
                                  enum:
                                    - AND
                                    - OR
                                conditions:
                                  type: array
                                  items:
                                    type: object
                                    properties:
                                      field:
                                        type: string
                                      operator:
                                        type: string
                                      value:
                                        anyOf:
                                          - type: string
                                          - type: number
                                          - type: boolean
                                          - type: array
                                            items:
                                              anyOf:
                                                - type: string
                                                - type: number
                                      type:
                                        type: string
                                        enum:
                                          - string
                                          - number
                                          - date
                                          - bool
                                    required:
                                      - field
                                      - operator
                              required:
                                - logicalOperator
                                - conditions
                            - type: object
                              properties:
                                actionType:
                                  type: string
                                mode:
                                  type: string
                                  enum:
                                    - engagement
                                sourceNodeId:
                                  type: string
                                window:
                                  type: object
                                  properties:
                                    duration:
                                      type: number
                                    unit:
                                      type: string
                                      enum:
                                        - ms
                                        - seconds
                                        - minutes
                                        - hours
                                        - days
                                        - weeks
                                  required:
                                    - duration
                                    - unit
                                branches:
                                  type: array
                                  items:
                                    type: object
                                    properties:
                                      id:
                                        type: string
                                      label:
                                        type: string
                                      condition:
                                        type: object
                                        properties:
                                          kind:
                                            type: string
                                            enum:
                                              - engaged
                                              - not_engaged
                                              - clicked_link
                                          events:
                                            type: string
                                            enum:
                                              - opened
                                              - clicked
                                              - opened_or_clicked
                                          url:
                                            type: string
                                          position:
                                            type: string
                                            enum:
                                              - any
                                              - first
                                              - last
                                        required:
                                          - kind
                                    required:
                                      - id
                                      - condition
                              required:
                                - mode
                                - sourceNodeId
                                - window
                                - branches
                      required:
                        - id
                        - label
                        - type
                        - config
                    - type: object
                      properties:
                        id:
                          type: string
                          minLength: 1
                        label:
                          type: string
                          minLength: 1
                        description:
                          type: string
                        type:
                          type: string
                          enum:
                            - split
                        config:
                          oneOf:
                            - type: object
                              properties:
                                actionType:
                                  type: string
                                mode:
                                  type: string
                                  enum:
                                    - percentage
                                leftLabel:
                                  type: string
                                rightLabel:
                                  type: string
                                leftPercentage:
                                  type: number
                                seed:
                                  type: string
                              required:
                                - mode
                                - leftLabel
                                - rightLabel
                                - leftPercentage
                            - type: object
                              properties:
                                actionType:
                                  type: string
                                mode:
                                  type: string
                                  enum:
                                    - condition
                                leftLabel:
                                  type: string
                                rightLabel:
                                  type: string
                                logicalOperator:
                                  type: string
                                  enum:
                                    - AND
                                    - OR
                                conditions:
                                  type: array
                                  items:
                                    type: object
                                    properties:
                                      field:
                                        type: string
                                      operator:
                                        type: string
                                      value:
                                        anyOf:
                                          - type: string
                                          - type: number
                                          - type: boolean
                                          - type: array
                                            items:
                                              anyOf:
                                                - type: string
                                                - type: number
                                      type:
                                        type: string
                                        enum:
                                          - string
                                          - number
                                          - date
                                          - bool
                                    required:
                                      - field
                                      - operator
                              required:
                                - mode
                                - leftLabel
                                - rightLabel
                                - logicalOperator
                                - conditions
                      required:
                        - id
                        - label
                        - type
                        - config
              connections:
                type: array
                items:
                  type: object
                  properties:
                    from:
                      type: string
                      minLength: 1
                    to:
                      type: string
                      minLength: 1
                    branch:
                      type: string
                  required:
                    - from
                    - to
              emailIds:
                type: array
                items:
                  type: string
                  minLength: 1
                  maxLength: 64
              createdBy:
                type: string
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time
              publishedAt:
                type: string
                format: date-time
              versions:
                type: array
                items:
                  type: object
                  properties:
                    version:
                      anyOf:
                        - type: integer
                          minimum: 0
                        - type: string
                          enum:
                            - latest
                    automationVersionId:
                      type: string
                      minLength: 1
                      maxLength: 64
                  required:
                    - version
                    - automationVersionId
                  additionalProperties: false
            required:
              - automationId
              - automationVersionId
              - name
              - version
              - published
              - emailIds
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
      additionalProperties: false
    AutomationsUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 120
        description:
          type: string
          maxLength: 2000
        nodes:
          type: array
          items:
            oneOf:
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - trigger
                  config:
                    anyOf:
                      - type: object
                        properties:
                          actionType:
                            type: string
                          eventName:
                            type: string
                          mode:
                            type: string
                            enum:
                              - event
                          triggerEventId:
                            type: string
                        additionalProperties: false
                      - type: object
                        properties:
                          actionType:
                            type: string
                          eventName:
                            type: string
                          mode:
                            type: string
                            enum:
                              - manualAudience
                          audienceId:
                            type: string
                        required:
                          - mode
                          - audienceId
                        additionalProperties: false
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - sendEmail
                  config:
                    type: object
                    properties:
                      actionType:
                        type: string
                        description: Informational duplicate of node.type; ignored.
                      emailId:
                        type: string
                        minLength: 1
                        description: Email design id — required for sendEmail.
                      emailVersionId:
                        type: string
                        minLength: 1
                        description: Exact email version id for deterministic delivery — required.
                      domainId:
                        type: string
                        minLength: 1
                        description: Owned, verified sending-domain id — optional at authoring; required at publish / live run.
                      subject:
                        type: string
                        minLength: 1
                        description: Inbox subject — required. Supports {{var | fallback}} interpolation.
                      previewText:
                        type: string
                        description: Inbox preheader — optional; the email design's <Preview> is the source of truth and wins when present.
                      messageClass:
                        type: string
                        enum:
                          - marketing
                          - transactional
                        description: Leftover snapshot; ignored at delivery — the class comes from the sending domain’s purpose (automations always send marketing-class mail).
                      fromName:
                        type: string
                        minLength: 1
                        description: Sender display name; resolved from the domain default when unset.
                      replyTo:
                        type: string
                        format: email
                        description: Reply-to address; resolved from the domain default when unset.
                      emailTitle:
                        type: string
                        description: Informational email title mirror; tolerated for round-trips.
                      fromAddress:
                        type: string
                        description: Sender address on a verified sending domain; resolved from the domain default when unset.
                    required:
                      - emailId
                      - emailVersionId
                      - subject
                    additionalProperties: false
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - wait
                  config:
                    type: object
                    properties:
                      actionType:
                        type: string
                      duration:
                        type: number
                      unit:
                        type: string
                        enum:
                          - ms
                          - seconds
                          - minutes
                          - hours
                          - days
                          - weeks
                    required:
                      - duration
                      - unit
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - filter
                  config:
                    anyOf:
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - payload
                          logicalOperator:
                            type: string
                            enum:
                              - AND
                              - OR
                          conditions:
                            type: array
                            items:
                              anyOf:
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - contains
                                        - not_contains
                                        - starts_with
                                        - ends_with
                                    value:
                                      type: string
                                      description: String value to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - gt
                                        - gte
                                        - lt
                                        - lte
                                    value:
                                      type: number
                                      description: Finite numeric value to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - gt
                                        - gte
                                        - lt
                                        - lte
                                    value:
                                      anyOf:
                                        - type: string
                                          minLength: 1
                                        - type: number
                                      description: ISO date string or Unix timestamp in milliseconds to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - in
                                        - not_in
                                        - contains_any
                                        - not_contains_any
                                    value:
                                      type: array
                                      items:
                                        type: string
                                        minLength: 1
                                      minItems: 1
                                      description: Non-empty array of string values to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - in
                                        - not_in
                                    value:
                                      type: array
                                      items:
                                        type: number
                                      minItems: 1
                                      description: Non-empty array of finite numbers to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - between
                                    value:
                                      type: array
                                      prefixItems:
                                        - type: number
                                        - type: number
                                      description: Inclusive [minimum, maximum] numeric bounds.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - between
                                    value:
                                      type: array
                                      prefixItems:
                                        - anyOf:
                                            - type: string
                                              minLength: 1
                                            - type: number
                                        - anyOf:
                                            - type: string
                                              minLength: 1
                                            - type: number
                                      description: Inclusive [start, end] ISO-date or Unix-millisecond timestamp bounds.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - bool
                                    operator:
                                      type: string
                                      enum:
                                        - is_true
                                        - is_false
                                      description: Unary boolean check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                            minItems: 1
                        required:
                          - logicalOperator
                          - conditions
                        additionalProperties: false
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - engagement
                          sourceNodeId:
                            type: string
                            minLength: 1
                            description: Id of the upstream sendEmail node this filter watches for opens/clicks.
                          window:
                            type: object
                            properties:
                              duration:
                                type: number
                                minimum: 0
                              unit:
                                type: string
                                enum:
                                  - ms
                                  - seconds
                                  - minutes
                                  - hours
                                  - days
                                  - weeks
                            required:
                              - duration
                              - unit
                            additionalProperties: false
                          branches:
                            type: array
                            items:
                              type: object
                              properties:
                                id:
                                  type: string
                                label:
                                  type: string
                                condition:
                                  type: object
                                  properties:
                                    kind:
                                      type: string
                                      enum:
                                        - engaged
                                        - not_engaged
                                        - clicked_link
                                    events:
                                      type: string
                                      enum:
                                        - opened
                                        - clicked
                                        - opened_or_clicked
                                    url:
                                      type: string
                                    position:
                                      type: string
                                      enum:
                                        - any
                                        - first
                                        - last
                                  required:
                                    - kind
                              required:
                                - id
                                - condition
                            minItems: 1
                        required:
                          - mode
                          - sourceNodeId
                          - window
                          - branches
                        additionalProperties: false
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
              - type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                  label:
                    type: string
                    minLength: 1
                  description:
                    type: string
                  type:
                    type: string
                    enum:
                      - split
                  config:
                    oneOf:
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - percentage
                          leftLabel:
                            type: string
                          rightLabel:
                            type: string
                          leftPercentage:
                            type: number
                            minimum: 0
                            maximum: 100
                          seed:
                            type: string
                        required:
                          - mode
                          - leftLabel
                          - rightLabel
                          - leftPercentage
                        additionalProperties: false
                      - type: object
                        properties:
                          actionType:
                            type: string
                          mode:
                            type: string
                            enum:
                              - condition
                          leftLabel:
                            type: string
                          rightLabel:
                            type: string
                          logicalOperator:
                            type: string
                            enum:
                              - AND
                              - OR
                          conditions:
                            type: array
                            items:
                              anyOf:
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - contains
                                        - not_contains
                                        - starts_with
                                        - ends_with
                                    value:
                                      type: string
                                      description: String value to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - gt
                                        - gte
                                        - lt
                                        - lte
                                    value:
                                      type: number
                                      description: Finite numeric value to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - equals
                                        - not_equals
                                        - gt
                                        - gte
                                        - lt
                                        - lte
                                    value:
                                      anyOf:
                                        - type: string
                                          minLength: 1
                                        - type: number
                                      description: ISO date string or Unix timestamp in milliseconds to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - in
                                        - not_in
                                        - contains_any
                                        - not_contains_any
                                    value:
                                      type: array
                                      items:
                                        type: string
                                        minLength: 1
                                      minItems: 1
                                      description: Non-empty array of string values to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - in
                                        - not_in
                                    value:
                                      type: array
                                      items:
                                        type: number
                                      minItems: 1
                                      description: Non-empty array of finite numbers to compare against.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - between
                                    value:
                                      type: array
                                      prefixItems:
                                        - type: number
                                        - type: number
                                      description: Inclusive [minimum, maximum] numeric bounds.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - between
                                    value:
                                      type: array
                                      prefixItems:
                                        - anyOf:
                                            - type: string
                                              minLength: 1
                                            - type: number
                                        - anyOf:
                                            - type: string
                                              minLength: 1
                                            - type: number
                                      description: Inclusive [start, end] ISO-date or Unix-millisecond timestamp bounds.
                                  required:
                                    - field
                                    - type
                                    - operator
                                    - value
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - string
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - number
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - date
                                    operator:
                                      type: string
                                      enum:
                                        - is_empty
                                        - is_not_empty
                                      description: Unary empty check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                                - type: object
                                  properties:
                                    field:
                                      type: string
                                      minLength: 1
                                      description: Trigger payload field name or dot path, for example trackingNumber or order.total.
                                    type:
                                      type: string
                                      enum:
                                        - bool
                                    operator:
                                      type: string
                                      enum:
                                        - is_true
                                        - is_false
                                      description: Unary boolean check; do not provide a value.
                                  required:
                                    - field
                                    - type
                                    - operator
                                  additionalProperties: false
                            minItems: 1
                        required:
                          - mode
                          - leftLabel
                          - rightLabel
                          - logicalOperator
                          - conditions
                        additionalProperties: false
                required:
                  - id
                  - label
                  - type
                  - config
                additionalProperties: false
          maxItems: 500
        connections:
          type: array
          items:
            type: object
            properties:
              from:
                type: string
                minLength: 1
              to:
                type: string
                minLength: 1
              branch:
                type: string
                minLength: 1
            required:
              - from
              - to
            additionalProperties: false
          maxItems: 1000
        triggerEventId:
          type: string
          minLength: 1
          maxLength: 256
        expectedBaseVersionId:
          type: string
          minLength: 1
          maxLength: 64
          description: "Optimistic concurrency guard: the exact version read before deriving this update. Supply together with expectedBaseDefinitionSha256."
        expectedBaseDefinitionSha256:
          type: string
          pattern: ^[a-f0-9]{64}$
          description: "Optimistic concurrency guard: SHA-256 of the exact definition read before deriving this update. Supply together with expectedBaseVersionId."
        dryRun:
          type: boolean
          description: Validate only — runs the full publish-gate check and returns blockers/warnings without writing.
        dry_run:
          type: boolean
          description: Accepted alias of `dryRun`.
        published:
          type: boolean
          description: "Lifecycle action: `true` validates + publishes the STORED latest version (a saved edit goes live only after this); `false` unpublishes. Cannot be combined with field/graph updates — update first, then publish."
        automationVersionId:
          type: string
          minLength: 1
          maxLength: 64
          description: "Exact version to publish; requires `published: true`."
        stop_in_flight:
          type: boolean
          description: "With `published: false` only — ALSO permanently stop contacts already mid-flow (default: they drain to completion)."
        paused:
          type: boolean
          description: Freeze (`true`) / resume (`false`) a LIVE automation without unpublishing; held contacts resume from the same point.
      additionalProperties: false
    AutomationsDeleteResponse:
      type: object
      properties:
        automationId:
          type: string
          minLength: 1
          maxLength: 64
        deleted:
          type: boolean
      required:
        - automationId
        - deleted
      additionalProperties: false
    AutomationRunStartedResponse:
      type: object
      properties:
        triggerInstanceId:
          type: string
          minLength: 4
          maxLength: 64
        automationRunIds:
          type: array
          items:
            type: string
            minLength: 1
            maxLength: 64
        status:
          type: string
          enum:
            - triggered
            - idempotent_replay
            - test_started
            - replay_started
        counts:
          type: object
          properties:
            automations:
              type: integer
              minimum: 0
            transactionalEmails:
              type: integer
              minimum: 0
          required:
            - automations
            - transactionalEmails
          additionalProperties: false
        receivedAt:
          type: string
          format: date-time
        warnings:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
              field:
                type: string
              message:
                type: string
              expectedType:
                type: string
              actualType:
                type: string
            required:
              - code
              - field
              - message
            additionalProperties: {}
      required:
        - automationRunIds
        - status
        - receivedAt
      additionalProperties: false
    AutomationTestRequest:
      type: object
      properties:
        payload:
          type: object
          additionalProperties: {}
        testRecipient:
          type: string
          format: email
      additionalProperties: false
    AutomationRunDryRunResponse:
      type: object
      properties:
        dry_run:
          type: boolean
          enum:
            - true
        automationId:
          type: string
        audienceId:
          type: string
        audienceName:
          type: string
        recipientCount:
          type: number
        sendNodeCount:
          type: number
        scheduledAt:
          type: string
      required:
        - dry_run
        - automationId
        - audienceId
        - recipientCount
        - sendNodeCount
    AudienceAutomationRunStartedResponse:
      type: object
      properties:
        audienceRunId:
          type: string
        automationId:
          type: string
        status:
          type: string
          enum:
            - queued
            - scheduled
        totalRecipients:
          type: number
        workflowRunId:
          type: string
        approvalState:
          type: string
          enum:
            - pending
          description: "Present when org-level send approval holds the run for admin review: no workflow starts until an admin approves; rejection cancels the run with zero deliveries."
        receivedAt:
          type: string
      required:
        - audienceRunId
        - automationId
        - status
        - totalRecipients
        - receivedAt
    AutomationRunRequest:
      type: object
      properties:
        dryRun:
          type: boolean
          description: Preview the recipient count + flow without launching a run (no sends, no side effects).
        dry_run:
          type: boolean
          description: Accepted alias of `dryRun`.
        scheduledAt:
          type: string
          format: date-time
        gradualSend:
          type: object
          properties:
            startingPercentage:
              type: number
              minimum: 0.1
              maximum: 100
            incrementPercentage:
              type: number
              minimum: 0
              maximum: 100
            interval:
              oneOf:
                - type: object
                  properties:
                    value:
                      type: integer
                      minimum: 1
                      maximum: 24
                    unit:
                      type: string
                      enum:
                        - hour
                  required:
                    - value
                    - unit
                  additionalProperties: false
                - type: object
                  properties:
                    value:
                      type: integer
                      minimum: 1
                      maximum: 30
                    unit:
                      type: string
                      enum:
                        - day
                  required:
                    - value
                    - unit
                  additionalProperties: false
            timeZone:
              type: string
              minLength: 1
              description: IANA timezone used to preserve local wall-clock time for day intervals.
          required:
            - startingPercentage
            - incrementPercentage
            - interval
            - timeZone
          additionalProperties: false
      additionalProperties: false
    AudienceRunsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              audienceRunId:
                type: string
              automationId:
                type: string
              automationName:
                type: string
              audienceId:
                type: string
              audienceName:
                type: string
              status:
                type: string
                enum:
                  - queued
                  - scheduled
                  - running
                  - paused
                  - sent
                  - failed
                  - canceled
              approvalState:
                type: string
                enum:
                  - pending
                  - approved
                  - rejected
              scheduledAt:
                type: string
              totalRecipients:
                type: number
              sentCount:
                type: number
              failedCount:
                type: number
              skippedCount:
                type: number
              nodeStats:
                type: array
                items:
                  type: object
                  properties:
                    nodeId:
                      type: string
                    nodeType:
                      type: string
                    status:
                      type: string
                      enum:
                        - running
                        - completed
                        - failed
                    entered:
                      type: number
                    sent:
                      type: number
                    failed:
                      type: number
                    skipped:
                      type: number
                  required:
                    - nodeId
                    - nodeType
              gradualSend:
                type: object
                properties:
                  startingPercentage:
                    type: number
                    minimum: 0.1
                    maximum: 100
                  incrementPercentage:
                    type: number
                    minimum: 0
                    maximum: 100
                  interval:
                    oneOf:
                      - type: object
                        properties:
                          value:
                            type: integer
                            minimum: 1
                            maximum: 24
                          unit:
                            type: string
                            enum:
                              - hour
                        required:
                          - value
                          - unit
                        additionalProperties: false
                      - type: object
                        properties:
                          value:
                            type: integer
                            minimum: 1
                            maximum: 30
                          unit:
                            type: string
                            enum:
                              - day
                        required:
                          - value
                          - unit
                        additionalProperties: false
                  timeZone:
                    type: string
                    minLength: 1
                    description: IANA timezone used to preserve local wall-clock time for day intervals.
                  rampEndsAt:
                    type: string
                    format: date-time
                  currentTranche:
                    type: integer
                    exclusiveMinimum: 0
                  sentSoFar:
                    type: integer
                    minimum: 0
                  pausedAt:
                    type: string
                    format: date-time
                  pauseReason:
                    type: string
                    enum:
                      - manual
                  resumedAt:
                    type: string
                    format: date-time
                required:
                  - startingPercentage
                  - incrementPercentage
                  - interval
                  - timeZone
                additionalProperties: false
              error:
                type: string
              startedAt:
                type: string
              completedAt:
                type: string
              createdAt:
                type: string
              updatedAt:
                type: string
            required:
              - audienceRunId
              - automationId
              - audienceId
              - status
              - createdAt
              - updatedAt
      required:
        - data
    AudienceRunControlResponse:
      type: object
      properties:
        audienceRunId:
          type: string
        status:
          type: string
          enum:
            - paused
            - running
            - canceled
      required:
        - audienceRunId
        - status
    AudienceRunControlRequest:
      type: object
      properties:
        action:
          type: string
          enum:
            - pause
            - resume
            - cancel
      required:
        - action
      additionalProperties: false
    AutomationRunsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              automationRunId:
                type: string
                minLength: 1
                maxLength: 64
              automationId:
                type: string
                minLength: 1
                maxLength: 64
              automationVersionId:
                type: string
                minLength: 1
                maxLength: 64
              triggerInstanceId:
                type: string
                minLength: 4
                maxLength: 64
              mode:
                type: string
                enum:
                  - live
                  - test
              status:
                type: string
                enum:
                  - pending
                  - running
                  - completed
                  - failed
                  - canceled
              recipientEmail:
                type: string
              startedAt:
                type: string
                format: date-time
              completedAt:
                type: string
                format: date-time
              error:
                type: string
              logs:
                type: array
                items:
                  type: object
                  properties:
                    automationRunId:
                      type: string
                      minLength: 1
                      maxLength: 64
                    nodeId:
                      type: string
                      minLength: 1
                    nodeName:
                      type: string
                      minLength: 1
                    nodeType:
                      type: string
                      enum:
                        - trigger
                        - wait
                        - filter
                        - split
                        - sendEmail
                    status:
                      type: string
                      enum:
                        - running
                        - success
                        - error
                        - skipped
                    orderIndex:
                      type: integer
                      minimum: 0
                    branch:
                      type: string
                      minLength: 1
                    durationMs:
                      type: integer
                      minimum: 0
                    startedAt:
                      type: string
                      format: date-time
                    completedAt:
                      type: string
                      format: date-time
                    error:
                      type: string
                  required:
                    - automationRunId
                    - nodeId
                    - nodeName
                    - nodeType
                    - status
                    - orderIndex
                    - startedAt
                  additionalProperties: false
            required:
              - automationRunId
              - automationId
              - mode
              - status
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
      additionalProperties: false
    TriggersPostRequest:
      type: object
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 120
        description:
          type: string
          maxLength: 2000
        payloadSchema:
          type: object
          properties:
            type:
              type: string
              enum:
                - object
            fields:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    minLength: 1
                    description: Variable name used by emails and automations, e.g. email or firstName. Prefer self-descriptive keys; this column has no separate description field.
                  type:
                    type: string
                    enum:
                      - string
                      - int
                      - boolean
                  required:
                    type: boolean
                  fallbackValue:
                    anyOf:
                      - type: string
                      - type: number
                      - type: boolean
                    description: Substitution value when the inbound payload is missing this field. Also used as the email agent's `e.g. {{ key | fallback }}` example.
                  pii:
                    type: string
                    enum:
                      - none
                      - low
                      - high
                    description: PII classification for redaction. "high" auto-redacts the value in execution logs and the inbound log. "low" (default when omitted) preserves the value. "none" is an explicit marker that the field is non-personal.
                required:
                  - key
                  - type
                  - required
          required:
            - type
            - fields
      required:
        - title
        - payloadSchema
      additionalProperties: false
    TriggersListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              triggerEventId:
                type: string
                minLength: 1
                maxLength: 256
              title:
                type: string
                minLength: 1
                maxLength: 120
              description:
                type: string
                maxLength: 2000
              provider:
                type: string
                enum:
                  - brew_api
                  - clerk
                  - stripe
                  - shopify
                  - stytch
                  - supabase
                  - workos
                  - revenuecat
                  - custom
              providerEventKey:
                type: string
              payloadSchema:
                type: object
                properties:
                  type:
                    type: string
                    enum:
                      - object
                  fields:
                    type: array
                    items:
                      type: object
                      properties:
                        key:
                          type: string
                          minLength: 1
                          description: Variable name used by emails and automations, e.g. email or firstName. Prefer self-descriptive keys; this column has no separate description field.
                        type:
                          type: string
                          enum:
                            - string
                            - int
                            - boolean
                        required:
                          type: boolean
                        fallbackValue:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                          description: Substitution value when the inbound payload is missing this field. Also used as the email agent's `e.g. {{ key | fallback }}` example.
                        pii:
                          type: string
                          enum:
                            - none
                            - low
                            - high
                          description: PII classification for redaction. "high" auto-redacts the value in execution logs and the inbound log. "low" (default when omitted) preserves the value. "none" is an explicit marker that the field is non-personal.
                      required:
                        - key
                        - type
                        - required
                required:
                  - type
                  - fields
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time
              skill:
                type: string
            required:
              - triggerEventId
              - title
              - provider
              - payloadSchema
              - createdAt
              - updatedAt
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
      additionalProperties: false
    TriggersPatchRequest:
      type: object
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 120
        description:
          type: string
          maxLength: 2000
        payloadSchema:
          type: object
          properties:
            type:
              type: string
              enum:
                - object
            fields:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    minLength: 1
                    description: Variable name used by emails and automations, e.g. email or firstName. Prefer self-descriptive keys; this column has no separate description field.
                  type:
                    type: string
                    enum:
                      - string
                      - int
                      - boolean
                  required:
                    type: boolean
                  fallbackValue:
                    anyOf:
                      - type: string
                      - type: number
                      - type: boolean
                    description: Substitution value when the inbound payload is missing this field. Also used as the email agent's `e.g. {{ key | fallback }}` example.
                  pii:
                    type: string
                    enum:
                      - none
                      - low
                      - high
                    description: PII classification for redaction. "high" auto-redacts the value in execution logs and the inbound log. "low" (default when omitted) preserves the value. "none" is an explicit marker that the field is non-personal.
                required:
                  - key
                  - type
                  - required
          required:
            - type
            - fields
      additionalProperties: false
    TriggersDeleteResponse:
      type: object
      properties:
        triggerEventId:
          type: string
          minLength: 1
          maxLength: 256
        deleted:
          type: boolean
      required:
        - triggerEventId
        - deleted
      additionalProperties: false
    TriggerFireResponse:
      type: object
      properties:
        success:
          type: boolean
        status:
          type: string
          enum:
            - triggered
            - idempotent_replay
            - ready
            - invalid_api_key
            - invalid_json
            - failed
            - forbidden
            - payload_mismatch
            - trigger_event_not_found
          description: 'Discriminator for the response category. Pairs with `code`. A trigger with no published automation attached returns `status: "failed"` + `code: "NO_PUBLISHED_AUTOMATION"` (HTTP 422). Successful fires always return `status: "triggered"`.'
        code:
          type: string
        message:
          type: string
        triggerEventId:
          type: string
        receivedAt:
          type: string
          description: ISO-8601 timestamp the request was processed at.
        details:
          type: object
          properties:
            resolvedPayload:
              type: object
              additionalProperties: {}
            warnings:
              type: array
              items:
                type: object
                properties:
                  code:
                    type: string
                  field:
                    type: string
                  message:
                    type: string
                  expectedType:
                    type: string
                  actualType:
                    type: string
                required:
                  - code
                  - field
                  - message
                additionalProperties: {}
            idempotencyKey:
              type: string
            triggerInstanceId:
              type: string
              description: Unique identifier for the persisted inbound row. Useful for support and replay. Set whenever an Idempotency-Key was provided.
            publishedTransactionalEmails:
              type: array
              items:
                type: object
                properties:
                  emailId:
                    type: string
                  title:
                    type: string
                required:
                  - emailId
                additionalProperties: {}
            publishedAutomations:
              type: array
              items:
                type: object
                properties:
                  automationId:
                    type: string
                  name:
                    type: string
                  primaryFromAddress:
                    type: string
                required:
                  - automationId
                additionalProperties: {}
            automationRunIds:
              type: array
              items:
                type: string
            counts:
              type: object
              properties:
                transactionalEmails:
                  type: integer
                automations:
                  type: integer
              required:
                - transactionalEmails
                - automations
          additionalProperties: {}
      required:
        - success
        - status
        - code
        - message
        - receivedAt
      additionalProperties: false
    TriggerFireRequest:
      type: object
      properties:
        payload:
          type: object
          additionalProperties: {}
          description: Event payload — fields and types must match the trigger's `payloadSchema`. Unknown fields are accepted but reported as `unexpected_key` warnings.
        idempotencyKey:
          type: string
          minLength: 1
          maxLength: 100
          description: Legacy body-field alternative to the `Idempotency-Key` HTTP header. Prefer the header for new integrations. The token is namespaced server-side with the API key org so different tenants cannot collide.
      required:
        - payload
      additionalProperties: false
    EventsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              triggerInstanceId:
                type: string
                minLength: 1
              source:
                type: string
                enum:
                  - api
                  - integration
              provider:
                type: string
              triggerEventId:
                type: string
                minLength: 1
                maxLength: 256
              state:
                type: string
                minLength: 1
              matchedAutomationIds:
                type: array
                items:
                  type: string
              automationRunIds:
                type: array
                items:
                  type: string
              rejectionReason:
                type: string
              attempts:
                type: integer
                minimum: 0
              receivedAt:
                type: string
                format: date-time
              processedAt:
                type: string
                format: date-time
            required:
              - triggerInstanceId
              - source
              - state
              - matchedAutomationIds
              - automationRunIds
              - attempts
              - receivedAt
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
      additionalProperties: false
    ContactsPostBatchResponse:
      type: object
      properties:
        summary:
          type: object
          properties:
            inserted:
              type: integer
              minimum: 0
            updated:
              type: integer
              minimum: 0
            failed:
              type: integer
              minimum: 0
          required:
            - inserted
            - updated
            - failed
          additionalProperties: false
        fieldsCreated:
          type: array
          items:
            type: string
        errors:
          type: array
          items:
            type: object
            properties:
              email:
                type: string
              code:
                type: string
              message:
                type: string
            required:
              - email
              - code
              - message
            additionalProperties: false
        warnings:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
                minLength: 1
              field:
                type: string
                minLength: 1
              message:
                type: string
                minLength: 1
              from:
                type: string
                minLength: 1
              to:
                type: string
                minLength: 1
              original:
                type: string
                minLength: 1
              normalized:
                type: string
                minLength: 1
            required:
              - code
              - message
            additionalProperties: false
        validation:
          type: object
          properties:
            valid:
              type: integer
              minimum: 0
            risky:
              type: integer
              minimum: 0
            invalid:
              type: integer
              minimum: 0
            unscored:
              type: integer
              minimum: 0
          required:
            - valid
            - risky
            - invalid
            - unscored
          additionalProperties: false
        validationJobId:
          type: string
      required:
        - summary
        - fieldsCreated
        - errors
        - warnings
      additionalProperties: false
    ContactsPostSingleResponse:
      type: object
      properties:
        contact:
          type: object
          properties:
            email:
              type: string
              format: email
            firstName:
              type: string
            lastName:
              type: string
            subscribed:
              type: boolean
              default: true
            validationStatus:
              type: string
              enum:
                - valid
                - risky
                - invalid
            verificationStatus:
              type: string
              enum:
                - valid
                - risky
                - invalid
              description: "Deprecated: legacy mirror of validationStatus. Will be removed; read validationStatus."
            suppressed:
              type: boolean
              default: false
            suppressedReason:
              type:
                - string
                - "null"
            lastValidatedAt:
              type: string
              format: date-time
            validationDetails:
              type: object
              properties:
                provider:
                  type: string
                  enum:
                    - brew
                reason:
                  type: string
                didYouMean:
                  type: string
                risk:
                  type: string
                isDisposable:
                  type: boolean
                isRole:
                  type: boolean
              required:
                - provider
              additionalProperties: false
            createdAt:
              type: string
              format: date-time
            updatedAt:
              type: string
              format: date-time
            importId:
              type:
                - string
                - "null"
            csvFileName:
              type:
                - string
                - "null"
            customFields:
              type: object
              additionalProperties: {}
              default: {}
          required:
            - email
            - createdAt
            - updatedAt
          additionalProperties: false
        created:
          type: boolean
        fieldsCreated:
          type: array
          items:
            type: string
        warnings:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
                minLength: 1
              field:
                type: string
                minLength: 1
              message:
                type: string
                minLength: 1
              from:
                type: string
                minLength: 1
              to:
                type: string
                minLength: 1
              original:
                type: string
                minLength: 1
              normalized:
                type: string
                minLength: 1
            required:
              - code
              - message
            additionalProperties: false
        validation:
          type: object
          properties:
            valid:
              type: integer
              minimum: 0
            risky:
              type: integer
              minimum: 0
            invalid:
              type: integer
              minimum: 0
            unscored:
              type: integer
              minimum: 0
          required:
            - valid
            - risky
            - invalid
            - unscored
          additionalProperties: false
      required:
        - contact
        - created
        - fieldsCreated
        - warnings
      additionalProperties: false
    ContactsPostRequest:
      anyOf:
        - $ref: "#/components/schemas/ContactsPostSingleRequest"
        - $ref: "#/components/schemas/ContactsPostBatchRequest"
    ContactsPostSingleRequest:
      type: object
      properties:
        email:
          type: string
          minLength: 1
        firstName:
          type: string
        lastName:
          type: string
        subscribed:
          type: boolean
        customFields:
          type: object
          additionalProperties: {}
        validate:
          type: boolean
          description: Optional deliverability check on ingestion. When true, each address is validated with the provider (2 credits per address, charged on success) and the verdict is saved to the contact’s `validationStatus`. Submissions above the inline cap (100 addresses) upsert first and validate as a background job, returning a `validationJobId`.
      required:
        - email
      additionalProperties: false
    ContactsPostBatchRequest:
      type: object
      properties:
        contacts:
          type: array
          items:
            type: object
            properties:
              email:
                type: string
              firstName:
                type: string
              lastName:
                type: string
              subscribed:
                type: boolean
              customFields:
                type: object
                additionalProperties: {}
            additionalProperties: false
          minItems: 1
          maxItems: 1000
        validate:
          type: boolean
          description: Optional deliverability check on ingestion. When true, each address is validated with the provider (2 credits per address, charged on success) and the verdict is saved to the contact’s `validationStatus`. Submissions above the inline cap (100 addresses) upsert first and validate as a background job, returning a `validationJobId`.
      required:
        - contacts
      additionalProperties: false
    ContactsPatchResponse:
      type: object
      properties:
        contact:
          type: object
          properties:
            email:
              type: string
              format: email
            firstName:
              type: string
            lastName:
              type: string
            subscribed:
              type: boolean
              default: true
            validationStatus:
              type: string
              enum:
                - valid
                - risky
                - invalid
            verificationStatus:
              type: string
              enum:
                - valid
                - risky
                - invalid
              description: "Deprecated: legacy mirror of validationStatus. Will be removed; read validationStatus."
            suppressed:
              type: boolean
              default: false
            suppressedReason:
              type:
                - string
                - "null"
            lastValidatedAt:
              type: string
              format: date-time
            validationDetails:
              type: object
              properties:
                provider:
                  type: string
                  enum:
                    - brew
                reason:
                  type: string
                didYouMean:
                  type: string
                risk:
                  type: string
                isDisposable:
                  type: boolean
                isRole:
                  type: boolean
              required:
                - provider
              additionalProperties: false
            createdAt:
              type: string
              format: date-time
            updatedAt:
              type: string
              format: date-time
            importId:
              type:
                - string
                - "null"
            csvFileName:
              type:
                - string
                - "null"
            customFields:
              type: object
              additionalProperties: {}
              default: {}
          required:
            - email
            - createdAt
            - updatedAt
          additionalProperties: false
        updated:
          type: array
          items:
            type: string
            minLength: 1
          minItems: 1
      required:
        - contact
        - updated
      additionalProperties: false
    ContactsPatchRequest:
      type: object
      properties:
        fields:
          type: object
          additionalProperties: {}
      required:
        - fields
      additionalProperties: false
    ContactDeleteResponse:
      type: object
      properties:
        email:
          type: string
          format: email
        deleted:
          type: boolean
      required:
        - email
        - deleted
      additionalProperties: false
    ContactsSearchSuccessResponse:
      anyOf:
        - $ref: "#/components/schemas/ContactsListResponse"
        - $ref: "#/components/schemas/ContactsCountResponse"
    ContactsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              email:
                type: string
                format: email
              firstName:
                type: string
              lastName:
                type: string
              subscribed:
                type: boolean
                default: true
              validationStatus:
                type: string
                enum:
                  - valid
                  - risky
                  - invalid
              verificationStatus:
                type: string
                enum:
                  - valid
                  - risky
                  - invalid
                description: "Deprecated: legacy mirror of validationStatus. Will be removed; read validationStatus."
              suppressed:
                type: boolean
                default: false
              suppressedReason:
                type:
                  - string
                  - "null"
              lastValidatedAt:
                type: string
                format: date-time
              validationDetails:
                type: object
                properties:
                  provider:
                    type: string
                    enum:
                      - brew
                  reason:
                    type: string
                  didYouMean:
                    type: string
                  risk:
                    type: string
                  isDisposable:
                    type: boolean
                  isRole:
                    type: boolean
                required:
                  - provider
                additionalProperties: false
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time
              importId:
                type:
                  - string
                  - "null"
              csvFileName:
                type:
                  - string
                  - "null"
              customFields:
                type: object
                additionalProperties: {}
                default: {}
            required:
              - email
              - createdAt
              - updatedAt
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
        - pagination
      additionalProperties: false
    ContactsCountResponse:
      type: object
      properties:
        count:
          type: integer
          minimum: 0
      required:
        - count
      additionalProperties: false
    ContactsSearchRequest:
      type: object
      properties:
        search:
          type: string
          minLength: 1
        filters:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
                minLength: 1
                description: The contact column or custom-field name to filter on (e.g. `email`, `firstName`, or a key from `list_custom_fields`).
              operator:
                type: string
                minLength: 1
                description: "One of: equals, not_equals, contains, not_contains, contains_any, not_contains_any, starts_with, ends_with, gt, gte, lt, lte, between, is_true, is_false, in, not_in, is_empty, not_exists, is_not_empty, exists, is_set, before, after, on_date. Unrecognized operators are ignored (the clause is dropped), so stick to this list — e.g. use `equals`, not `eq`."
              value:
                type: string
                description: The comparison value, as a string. Unary operators (`is_set`, `is_empty`, `exists`, …) ignore it — pass "".
            required:
              - field
              - operator
              - value
            additionalProperties: false
          default: []
        audienceId:
          type: string
          minLength: 1
        logic:
          type: string
          enum:
            - and
            - or
            - none
          default: and
        sort:
          type: string
          minLength: 1
          default: createdAt
        order:
          type: string
          enum:
            - asc
            - desc
          default: desc
        count:
          type: boolean
          default: false
        limit:
          type: integer
          minimum: 1
          maximum: 100
          default: 50
        cursor:
          type: string
          minLength: 1
      additionalProperties: false
    ContactsValidateResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              email:
                type: string
              valid:
                type: boolean
              status:
                type: string
                enum:
                  - valid
                  - risky
                  - invalid
              reason:
                type: string
              didYouMean:
                type: string
              risk:
                type: string
              isDisposable:
                type: boolean
              isRole:
                type: boolean
            required:
              - email
              - valid
              - status
            additionalProperties: false
      required:
        - data
      additionalProperties: false
    ContactsValidateRequest:
      type: object
      properties:
        emails:
          type: array
          items:
            type: string
            minLength: 1
          minItems: 1
          maxItems: 100
      required:
        - emails
      additionalProperties: false
    ContactsImportCsvResponse:
      type: object
      properties:
        summary:
          type: object
          properties:
            inserted:
              type: integer
              minimum: 0
            updated:
              type: integer
              minimum: 0
            failed:
              type: integer
              minimum: 0
            skipped:
              type: integer
              minimum: 0
          required:
            - inserted
            - updated
            - failed
            - skipped
          additionalProperties: false
        fieldsCreated:
          type: array
          items:
            type: string
        errors:
          type: array
          items:
            type: object
            properties:
              email:
                type: string
              code:
                type: string
              message:
                type: string
            required:
              - email
              - code
              - message
            additionalProperties: false
        warnings:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
                minLength: 1
              field:
                type: string
                minLength: 1
              message:
                type: string
                minLength: 1
              from:
                type: string
                minLength: 1
              to:
                type: string
                minLength: 1
              original:
                type: string
                minLength: 1
              normalized:
                type: string
                minLength: 1
            required:
              - code
              - message
            additionalProperties: false
        validation:
          type: object
          properties:
            valid:
              type: integer
              minimum: 0
            risky:
              type: integer
              minimum: 0
            invalid:
              type: integer
              minimum: 0
            unscored:
              type: integer
              minimum: 0
          required:
            - valid
            - risky
            - invalid
            - unscored
          additionalProperties: false
        validationJobId:
          type: string
      required:
        - summary
        - fieldsCreated
        - errors
        - warnings
      additionalProperties: false
    ContactsImportCsvRequest:
      type: object
      properties:
        csv:
          type: string
          minLength: 1
          maxLength: 5000000
        mapping:
          type: object
          additionalProperties:
            type: string
        validate:
          type: boolean
          description: Optional deliverability check on ingestion. When true, each address is validated with the provider (2 credits per address, charged on success) and the verdict is saved to the contact’s `validationStatus`. Submissions above the inline cap (100 addresses) upsert first and validate as a background job, returning a `validationJobId`.
      required:
        - csv
      additionalProperties: false
    ContactsBatchDeleteResponse:
      type: object
      properties:
        deleted:
          type: integer
          minimum: 0
        notFound:
          type: array
          items:
            type: string
            minLength: 1
      required:
        - deleted
      additionalProperties: false
    ContactsBatchDeleteRequest:
      type: object
      properties:
        emails:
          type: array
          items:
            type: string
            format: email
          minItems: 1
          maxItems: 1000
      required:
        - emails
      additionalProperties: false
    FieldsGetResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              fieldName:
                type: string
                minLength: 1
              fieldType:
                type: string
                enum:
                  - string
                  - number
                  - date
                  - bool
              label:
                type: string
              isCore:
                type: boolean
              isFilterable:
                type: boolean
              isSortable:
                type: boolean
              isSearchable:
                type: boolean
              coverage:
                type: object
                properties:
                  percent:
                    type: integer
                    minimum: 0
                    maximum: 100
                  approximate:
                    type: boolean
                  topValues:
                    type: array
                    items:
                      type: object
                      properties:
                        value:
                          type: string
                        count:
                          type: integer
                          minimum: 0
                        percent:
                          type: integer
                          minimum: 0
                          maximum: 100
                      required:
                        - value
                        - count
                        - percent
                      additionalProperties: false
                  dominantValue:
                    type: string
                required:
                  - percent
                  - approximate
                  - topValues
                additionalProperties: false
            required:
              - fieldName
              - fieldType
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
        - pagination
      additionalProperties: false
    FieldsPostRequest:
      type: object
      properties:
        fieldName:
          type: string
          minLength: 1
        fieldType:
          type: string
          enum:
            - string
            - number
            - date
            - bool
      required:
        - fieldName
        - fieldType
      additionalProperties: false
    FieldsDeleteResponse:
      type: object
      properties:
        fieldName:
          type: string
          minLength: 1
        deleted:
          type: boolean
      required:
        - fieldName
        - deleted
      additionalProperties: false
    AudiencesListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              audienceId:
                type: string
                minLength: 1
                maxLength: 64
              audienceName:
                type: string
                minLength: 1
                maxLength: 200
              filters:
                type: object
                properties:
                  filters:
                    type: array
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                          minLength: 1
                        operator:
                          type: string
                          enum:
                            - equals
                            - not_equals
                            - contains
                            - not_contains
                            - contains_any
                            - not_contains_any
                            - starts_with
                            - ends_with
                            - gt
                            - gte
                            - lt
                            - lte
                            - between
                            - is_true
                            - is_false
                            - in
                            - not_in
                            - is_empty
                            - not_exists
                            - is_not_empty
                            - exists
                            - is_set
                            - before
                            - after
                            - on_date
                        value: {}
                        type:
                          type: string
                          description: The field's value type — set `number`, `date`, or `boolean` for typed comparisons (dates are stored as epoch-ms, so a string `equals` on a date never matches). Omit for plain string fields.
                      required:
                        - field
                        - operator
                      additionalProperties: false
                  logicalOperator:
                    type: string
                    enum:
                      - and
                      - or
                required:
                  - filters
                  - logicalOperator
                additionalProperties: false
              count:
                type: integer
                minimum: 0
              materializationStatus:
                type: string
                enum:
                  - pending
                  - running
                  - ready
                  - failed
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time
              build:
                type: object
                properties:
                  jobId:
                    type: string
                    minLength: 1
                    maxLength: 64
                  status:
                    type: string
                    enum:
                      - pending
                      - running
                      - completed
                      - partial
                      - failed
                  cohort:
                    type: object
                    properties:
                      eventTypes:
                        type: array
                        items:
                          type: string
                          enum:
                            - sent
                            - delivered
                            - delivery_delayed
                            - opened
                            - clicked
                            - bounced
                            - complained
                            - failed
                            - skipped
                            - unsubscribed
                        minItems: 1
                        maxItems: 10
                      from:
                        type: string
                        format: date-time
                      to:
                        type: string
                        format: date-time
                        description: Defaults to now.
                      sendId:
                        type: string
                        minLength: 1
                        maxLength: 64
                      emailId:
                        type: string
                        minLength: 1
                        maxLength: 64
                      automationIds:
                        type: array
                        items:
                          type: string
                          minLength: 1
                          maxLength: 64
                        maxItems: 20
                      audienceIds:
                        type: array
                        items:
                          type: string
                          minLength: 1
                          maxLength: 64
                        maxItems: 20
                        description: Scope to events from sends that targeted these audiences.
                      recipient:
                        type: array
                        items:
                          type: string
                          minLength: 1
                          maxLength: 320
                        maxItems: 10
                        description: Recipient rule tokens using the Events-page grammar.
                      includeMachineClicks:
                        type: boolean
                    required:
                      - eventTypes
                      - from
                      - to
                    additionalProperties: false
                  field:
                    type: object
                    properties:
                      key:
                        type: string
                        minLength: 1
                      label:
                        type: string
                        minLength: 1
                      type:
                        type: string
                        enum:
                          - date
                    required:
                      - key
                      - label
                      - type
                    additionalProperties: false
                  counts:
                    type: object
                    properties:
                      eventsScanned:
                        type: integer
                        minimum: 0
                      stampedContacts:
                        type: integer
                        minimum: 0
                    required:
                      - eventsScanned
                    additionalProperties: false
                  error:
                    type: string
                  enqueuedAt:
                    type: string
                    format: date-time
                  completedAt:
                    type: string
                    format: date-time
                required:
                  - jobId
                  - status
                  - cohort
                  - field
                  - counts
                  - enqueuedAt
                additionalProperties: false
            required:
              - audienceId
              - audienceName
              - filters
              - count
              - createdAt
              - updatedAt
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
      additionalProperties: false
    AudienceWriteResponse:
      type: object
      properties:
        audienceId:
          type: string
          minLength: 1
          maxLength: 64
        audienceName:
          type: string
          minLength: 1
          maxLength: 200
        filters:
          type: object
          properties:
            filters:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    minLength: 1
                  operator:
                    type: string
                    enum:
                      - equals
                      - not_equals
                      - contains
                      - not_contains
                      - contains_any
                      - not_contains_any
                      - starts_with
                      - ends_with
                      - gt
                      - gte
                      - lt
                      - lte
                      - between
                      - is_true
                      - is_false
                      - in
                      - not_in
                      - is_empty
                      - not_exists
                      - is_not_empty
                      - exists
                      - is_set
                      - before
                      - after
                      - on_date
                  value: {}
                  type:
                    type: string
                    description: The field's value type — set `number`, `date`, or `boolean` for typed comparisons (dates are stored as epoch-ms, so a string `equals` on a date never matches). Omit for plain string fields.
                required:
                  - field
                  - operator
                additionalProperties: false
            logicalOperator:
              type: string
              enum:
                - and
                - or
          required:
            - filters
            - logicalOperator
          additionalProperties: false
        count:
          type: integer
          minimum: 0
        materializationStatus:
          type: string
          enum:
            - pending
            - running
            - ready
            - failed
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        build:
          type: object
          properties:
            jobId:
              type: string
              minLength: 1
              maxLength: 64
            status:
              type: string
              enum:
                - pending
                - running
                - completed
                - partial
                - failed
            cohort:
              type: object
              properties:
                eventTypes:
                  type: array
                  items:
                    type: string
                    enum:
                      - sent
                      - delivered
                      - delivery_delayed
                      - opened
                      - clicked
                      - bounced
                      - complained
                      - failed
                      - skipped
                      - unsubscribed
                  minItems: 1
                  maxItems: 10
                from:
                  type: string
                  format: date-time
                to:
                  type: string
                  format: date-time
                  description: Defaults to now.
                sendId:
                  type: string
                  minLength: 1
                  maxLength: 64
                emailId:
                  type: string
                  minLength: 1
                  maxLength: 64
                automationIds:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 64
                  maxItems: 20
                audienceIds:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 64
                  maxItems: 20
                  description: Scope to events from sends that targeted these audiences.
                recipient:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 320
                  maxItems: 10
                  description: Recipient rule tokens using the Events-page grammar.
                includeMachineClicks:
                  type: boolean
              required:
                - eventTypes
                - from
                - to
              additionalProperties: false
            field:
              type: object
              properties:
                key:
                  type: string
                  minLength: 1
                label:
                  type: string
                  minLength: 1
                type:
                  type: string
                  enum:
                    - date
              required:
                - key
                - label
                - type
              additionalProperties: false
            counts:
              type: object
              properties:
                eventsScanned:
                  type: integer
                  minimum: 0
                stampedContacts:
                  type: integer
                  minimum: 0
              required:
                - eventsScanned
              additionalProperties: false
            error:
              type: string
            enqueuedAt:
              type: string
              format: date-time
            completedAt:
              type: string
              format: date-time
          required:
            - jobId
            - status
            - cohort
            - field
            - counts
            - enqueuedAt
          additionalProperties: false
        emailListMaterializations:
          type: array
          items:
            type: object
            properties:
              fieldName:
                type: string
                description: Custom-field key the address list was stamped onto.
              providedEmails:
                type: integer
                description: Distinct addresses supplied after normalization.
              matchedContacts:
                type: integer
                description: Addresses that matched an EXISTING contact and were stamped — a gap vs `providedEmails` means those addresses have no contact record (import them first).
            required:
              - fieldName
              - providedEmails
              - matchedContacts
            additionalProperties: false
          description: Present when an `email in [...]` clause with more than 100 addresses was auto-converted into a stamped custom-field snapshot.
      required:
        - audienceId
        - audienceName
        - filters
        - count
        - createdAt
        - updatedAt
      additionalProperties: false
    AudiencesPostRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 200
        filters:
          type: object
          properties:
            filters:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    minLength: 1
                  operator:
                    type: string
                    enum:
                      - equals
                      - not_equals
                      - contains
                      - not_contains
                      - contains_any
                      - not_contains_any
                      - starts_with
                      - ends_with
                      - gt
                      - gte
                      - lt
                      - lte
                      - between
                      - is_true
                      - is_false
                      - in
                      - not_in
                      - is_empty
                      - not_exists
                      - is_not_empty
                      - exists
                      - is_set
                      - before
                      - after
                      - on_date
                  value: {}
                  type:
                    type: string
                    description: The field's value type — set `number`, `date`, or `boolean` for typed comparisons (dates are stored as epoch-ms, so a string `equals` on a date never matches). Omit for plain string fields.
                required:
                  - field
                  - operator
                additionalProperties: false
              minItems: 1
            logicalOperator:
              type: string
              enum:
                - and
                - or
          required:
            - filters
            - logicalOperator
          additionalProperties: false
          description: 'Filter clauses combined by `logicalOperator`. For specific addresses use `{ field: "email", operator: "in", value: ["a@x.com", ...] }` — a list over 100 addresses is auto-converted into a stamped custom-field snapshot of the listed EXISTING contacts (addresses without a contact record are skipped; 10,000 max).'
      required:
        - name
        - filters
      additionalProperties: false
    AudiencesFromEventsResponse:
      type: object
      properties:
        audienceId:
          type: string
          minLength: 1
          maxLength: 64
        audienceName:
          type: string
          minLength: 1
          maxLength: 200
        filters:
          type: object
          properties:
            filters:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    minLength: 1
                  operator:
                    type: string
                    enum:
                      - equals
                      - not_equals
                      - contains
                      - not_contains
                      - contains_any
                      - not_contains_any
                      - starts_with
                      - ends_with
                      - gt
                      - gte
                      - lt
                      - lte
                      - between
                      - is_true
                      - is_false
                      - in
                      - not_in
                      - is_empty
                      - not_exists
                      - is_not_empty
                      - exists
                      - is_set
                      - before
                      - after
                      - on_date
                  value: {}
                  type:
                    type: string
                    description: The field's value type — set `number`, `date`, or `boolean` for typed comparisons (dates are stored as epoch-ms, so a string `equals` on a date never matches). Omit for plain string fields.
                required:
                  - field
                  - operator
                additionalProperties: false
            logicalOperator:
              type: string
              enum:
                - and
                - or
          required:
            - filters
            - logicalOperator
          additionalProperties: false
        count:
          type: integer
          minimum: 0
        materializationStatus:
          type: string
          enum:
            - pending
            - running
            - ready
            - failed
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        build:
          type: object
          properties:
            jobId:
              type: string
              minLength: 1
              maxLength: 64
            status:
              type: string
              enum:
                - pending
                - running
                - completed
                - partial
                - failed
            cohort:
              type: object
              properties:
                eventTypes:
                  type: array
                  items:
                    type: string
                    enum:
                      - sent
                      - delivered
                      - delivery_delayed
                      - opened
                      - clicked
                      - bounced
                      - complained
                      - failed
                      - skipped
                      - unsubscribed
                  minItems: 1
                  maxItems: 10
                from:
                  type: string
                  format: date-time
                to:
                  type: string
                  format: date-time
                  description: Defaults to now.
                sendId:
                  type: string
                  minLength: 1
                  maxLength: 64
                emailId:
                  type: string
                  minLength: 1
                  maxLength: 64
                automationIds:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 64
                  maxItems: 20
                audienceIds:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 64
                  maxItems: 20
                  description: Scope to events from sends that targeted these audiences.
                recipient:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 320
                  maxItems: 10
                  description: Recipient rule tokens using the Events-page grammar.
                includeMachineClicks:
                  type: boolean
              required:
                - eventTypes
                - from
                - to
              additionalProperties: false
            field:
              type: object
              properties:
                key:
                  type: string
                  minLength: 1
                label:
                  type: string
                  minLength: 1
                type:
                  type: string
                  enum:
                    - date
              required:
                - key
                - label
                - type
              additionalProperties: false
            counts:
              type: object
              properties:
                eventsScanned:
                  type: integer
                  minimum: 0
                stampedContacts:
                  type: integer
                  minimum: 0
              required:
                - eventsScanned
              additionalProperties: false
            error:
              type: string
            enqueuedAt:
              type: string
              format: date-time
            completedAt:
              type: string
              format: date-time
          required:
            - jobId
            - status
            - cohort
            - field
            - counts
            - enqueuedAt
          additionalProperties: false
      required:
        - audienceId
        - audienceName
        - filters
        - count
        - materializationStatus
        - createdAt
        - updatedAt
        - build
      additionalProperties: false
    AudiencesFromEventsRequest:
      type: object
      properties:
        cohort:
          type: object
          properties:
            eventTypes:
              type: array
              items:
                type: string
                enum:
                  - sent
                  - delivered
                  - delivery_delayed
                  - opened
                  - clicked
                  - bounced
                  - complained
                  - failed
                  - skipped
                  - unsubscribed
              minItems: 1
              maxItems: 10
            from:
              type: string
              format: date-time
            to:
              type: string
              format: date-time
              description: Defaults to now.
            sendId:
              type: string
              minLength: 1
              maxLength: 64
            emailId:
              type: string
              minLength: 1
              maxLength: 64
            automationIds:
              type: array
              items:
                type: string
                minLength: 1
                maxLength: 64
              maxItems: 20
            audienceIds:
              type: array
              items:
                type: string
                minLength: 1
                maxLength: 64
              maxItems: 20
              description: Scope to events from sends that targeted these audiences.
            recipient:
              type: array
              items:
                type: string
                minLength: 1
                maxLength: 320
              maxItems: 10
              description: Recipient rule tokens using the Events-page grammar.
            includeMachineClicks:
              type: boolean
          required:
            - eventTypes
            - from
          additionalProperties: false
        name:
          type: string
          minLength: 1
          maxLength: 200
      required:
        - cohort
      additionalProperties: false
    AudiencesPatchRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 200
        filters:
          type: object
          properties:
            filters:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    minLength: 1
                  operator:
                    type: string
                    enum:
                      - equals
                      - not_equals
                      - contains
                      - not_contains
                      - contains_any
                      - not_contains_any
                      - starts_with
                      - ends_with
                      - gt
                      - gte
                      - lt
                      - lte
                      - between
                      - is_true
                      - is_false
                      - in
                      - not_in
                      - is_empty
                      - not_exists
                      - is_not_empty
                      - exists
                      - is_set
                      - before
                      - after
                      - on_date
                  value: {}
                  type:
                    type: string
                    description: The field's value type — set `number`, `date`, or `boolean` for typed comparisons (dates are stored as epoch-ms, so a string `equals` on a date never matches). Omit for plain string fields.
                required:
                  - field
                  - operator
                additionalProperties: false
              minItems: 1
            logicalOperator:
              type: string
              enum:
                - and
                - or
          required:
            - filters
            - logicalOperator
          additionalProperties: false
          description: 'Filter clauses combined by `logicalOperator`. For specific addresses use `{ field: "email", operator: "in", value: ["a@x.com", ...] }` — a list over 100 addresses is auto-converted into a stamped custom-field snapshot of the listed EXISTING contacts (addresses without a contact record are skipped; 10,000 max).'
        expectedUpdatedAt:
          type: string
          format: date-time
          description: Optional optimistic-concurrency precondition from the latest audience read. The update returns 409 if the row changed meanwhile.
      additionalProperties: false
    AudiencesDeleteResponse:
      type: object
      properties:
        audienceId:
          type: string
          minLength: 1
          maxLength: 64
        deleted:
          type: boolean
      required:
        - audienceId
        - deleted
      additionalProperties: false
    DomainsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              domainId:
                type: string
                minLength: 1
                maxLength: 64
              domainUrl:
                type: string
                format: uri
              name:
                type: string
                minLength: 1
                maxLength: 253
              region:
                type: string
              status:
                type: string
                enum:
                  - not_started
                  - pending
                  - verified
                  - failed
                  - temporary_failure
                  - partially_verified
                  - partially_failed
              sendingEnabled:
                type: boolean
              sendable:
                type: boolean
              sendingPurpose:
                type: string
                enum:
                  - marketing
                  - transactional
                description: marketing (default) or transactional. Transactional domains skip unsubscribe and may only send via API/MCP inline `to` (or a test send).
              records:
                type: array
                items:
                  type: object
                  properties:
                    record:
                      type: string
                    name:
                      type: string
                    type:
                      type: string
                    ttl:
                      type: string
                    status:
                      type: string
                    value:
                      type: string
                    priority:
                      type: number
                  required:
                    - record
                    - name
                    - type
                    - ttl
                    - status
                    - value
                  additionalProperties: false
              openTracking:
                type: boolean
              clickTracking:
                type: boolean
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time
              verifiedAt:
                type: string
                format: date-time
            required:
              - domainId
              - domainUrl
              - name
              - region
              - status
              - sendingEnabled
              - sendable
              - sendingPurpose
              - records
              - createdAt
              - updatedAt
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
      additionalProperties: false
    DomainsPostRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 253
        region:
          type: string
          enum:
            - us-east-1
        customReturnPath:
          type: string
          minLength: 1
          maxLength: 64
        sendingPurpose:
          type: string
          enum:
            - marketing
            - transactional
          default: marketing
          description: marketing (default) for campaigns and automations, or transactional for API/MCP inline `to` only.
      required:
        - name
      additionalProperties: false
    DomainsPatchRequest:
      type: object
      properties:
        defaultSenderName:
          type: string
          maxLength: 120
        defaultFromEmail:
          type: string
          format: email
        defaultReplyToEmail:
          type: string
          format: email
        sendingPurpose:
          type: string
          enum:
            - marketing
            - transactional
          description: Change the domain purpose. Live gates fail closed if a campaign or automation still points at a transactional domain.
      additionalProperties: false
    DomainsDeleteResponse:
      type: object
      properties:
        domainId:
          type: string
          minLength: 1
          maxLength: 64
        deleted:
          type: boolean
      required:
        - domainId
        - deleted
      additionalProperties: false
    DomainHealth:
      type: object
      properties:
        domainId:
          type: string
          minLength: 1
          maxLength: 64
        name:
          type: string
          minLength: 1
          maxLength: 253
        status:
          type: string
          enum:
            - not_started
            - pending
            - verified
            - failed
            - temporary_failure
            - partially_verified
            - partially_failed
        sendable:
          type: boolean
        verdict:
          type: string
          enum:
            - healthy
            - at_risk
            - critical
        readiness:
          type: string
          enum:
            - ready
            - ready_with_warnings
            - not_ready
            - checking
            - unknown
        score:
          type: object
          properties:
            value:
              type: integer
              minimum: 0
              maximum: 100
            grade:
              type: string
              enum:
                - excellent
                - good
                - fair
                - poor
                - critical
            confidence:
              type: string
              enum:
                - high
                - medium
                - low
            components:
              type: object
              properties:
                placement:
                  type: object
                  properties:
                    score:
                      type: integer
                      minimum: 0
                      maximum: 100
                    weight:
                      type: number
                      minimum: 0
                      maximum: 1
                    basis:
                      type: string
                  required:
                    - score
                    - weight
                    - basis
                  additionalProperties: false
                authentication:
                  type: object
                  properties:
                    score:
                      type: integer
                      minimum: 0
                      maximum: 100
                    weight:
                      type: number
                      minimum: 0
                      maximum: 1
                    basis:
                      type: string
                  required:
                    - score
                    - weight
                    - basis
                  additionalProperties: false
                reputation:
                  type: object
                  properties:
                    score:
                      type: integer
                      minimum: 0
                      maximum: 100
                    weight:
                      type: number
                      minimum: 0
                      maximum: 1
                    basis:
                      type: string
                  required:
                    - score
                    - weight
                    - basis
                  additionalProperties: false
                content:
                  type: object
                  properties:
                    score:
                      type: integer
                      minimum: 0
                      maximum: 100
                    weight:
                      type: number
                      minimum: 0
                      maximum: 1
                    basis:
                      type: string
                  required:
                    - score
                    - weight
                    - basis
                  additionalProperties: false
                posture:
                  type: object
                  properties:
                    score:
                      type: integer
                      minimum: 0
                      maximum: 100
                    weight:
                      type: number
                      minimum: 0
                      maximum: 1
                    basis:
                      type: string
                  required:
                    - score
                    - weight
                    - basis
                  additionalProperties: false
              required:
                - placement
                - authentication
                - reputation
                - content
                - posture
              additionalProperties: false
            trend:
              type:
                - object
                - "null"
              properties:
                direction:
                  type: string
                  enum:
                    - up
                    - down
                    - flat
                previousScore:
                  type: integer
                  minimum: 0
                  maximum: 100
                previousComputedAt:
                  type: string
                  format: date-time
              required:
                - direction
                - previousScore
                - previousComputedAt
              additionalProperties: false
          required:
            - value
            - grade
            - confidence
            - components
            - trend
          additionalProperties: false
        authentication:
          type: object
          properties:
            spf:
              type: string
              enum:
                - verified
                - pending
                - failed
                - missing
            dkim:
              type: string
              enum:
                - verified
                - pending
                - failed
                - missing
            dmarc:
              type: string
              enum:
                - verified
                - pending
                - missing
          required:
            - spf
            - dkim
            - dmarc
          additionalProperties: false
        tracking:
          type: object
          properties:
            linksStatus:
              type: string
              enum:
                - live
                - no_cert
                - unreachable
                - unknown
            openTracking:
              type: boolean
            clickTracking:
              type: boolean
          additionalProperties: false
        warmup:
          type: array
          items:
            type: object
            properties:
              sendId:
                type: string
              currentTranche:
                type: integer
              sentSoFar:
                type: integer
              pausedAt:
                type: string
              pauseReason:
                type: string
              rampEndsAt:
                type: string
            required:
              - sendId
            additionalProperties: false
        dailyVolume:
          type: array
          items:
            type: object
            properties:
              day:
                type: string
              sent:
                type: integer
                minimum: 0
            required:
              - day
              - sent
            additionalProperties: false
        domainActivity:
          type:
            - object
            - "null"
          properties:
            sampled:
              type: boolean
              enum:
                - true
            sampleSendCount:
              type: integer
              minimum: 0
            sentCount:
              type: integer
              minimum: 0
            deliveredCount:
              type: integer
              minimum: 0
            bouncedCount:
              type: integer
              minimum: 0
            complainedCount:
              type: integer
              minimum: 0
            bounceRate:
              type:
                - number
                - "null"
            complaintRate:
              type:
                - number
                - "null"
          required:
            - sampled
            - sampleSendCount
            - sentCount
            - deliveredCount
            - bouncedCount
            - complainedCount
            - bounceRate
            - complaintRate
          additionalProperties: false
        orgReputation:
          type:
            - object
            - "null"
          properties:
            scope:
              type: string
              enum:
                - org
            totalSent:
              type: integer
              minimum: 0
            bounceRate:
              type:
                - number
                - "null"
            complaintRate:
              type:
                - number
                - "null"
          required:
            - scope
            - totalSent
            - bounceRate
            - complaintRate
          additionalProperties: false
        recentPlacementTests:
          type: array
          items:
            type: object
            properties:
              testId:
                type: string
              emailId:
                type: string
              status:
                type: string
              overall:
                type:
                  - object
                  - "null"
                properties:
                  total:
                    type: integer
                    minimum: 0
                  inbox:
                    type: integer
                    minimum: 0
                  spam:
                    type: integer
                    minimum: 0
                  missing:
                    type: integer
                    minimum: 0
                  pending:
                    type: integer
                    minimum: 0
                required:
                  - total
                  - inbox
                  - spam
                  - missing
                  - pending
              authentication:
                type:
                  - object
                  - "null"
                properties:
                  spf:
                    type: string
                  dkim:
                    type: string
                  dmarc:
                    type: string
                additionalProperties: false
              spamFilterFlagged:
                type: boolean
              source:
                type: string
              variant:
                type: string
              createdAt:
                type: string
                format: date-time
            required:
              - testId
              - emailId
              - status
              - overall
              - authentication
              - spamFilterFlagged
              - createdAt
            additionalProperties: false
        signals:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                enum:
                  - domain_not_verified
                  - dns_record_failed
                  - dmarc_missing
                  - sending_disabled
                  - tracking_links_broken
                  - high_bounce_rate
                  - high_complaint_rate
                  - placement_spam_heavy
                  - content_spam_filter_flagged
                  - auth_failing_in_tests
                  - placement_baseline_spam
                  - content_image_weight_penalty
                  - content_promotional_penalty
                  - content_promotions_tab_shift
                  - warmup_paused
              severity:
                type: string
                enum:
                  - critical
                  - warning
                  - info
              summary:
                type: string
              suggestion:
                type: string
              action:
                type: object
                properties:
                  tool:
                    type: string
                  note:
                    type: string
                required:
                  - tool
                additionalProperties: false
            required:
              - id
              - severity
              - summary
              - suggestion
            additionalProperties: false
        checkedAt:
          type: string
          format: date-time
      required:
        - domainId
        - name
        - status
        - sendable
        - verdict
        - readiness
        - score
        - authentication
        - tracking
        - warmup
        - dailyVolume
        - domainActivity
        - orgReputation
        - recentPlacementTests
        - signals
        - checkedAt
      additionalProperties: false
    TemplatesListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              emailId:
                type: string
                minLength: 1
              title:
                type: string
                minLength: 1
              category:
                type: string
                minLength: 1
              brand:
                type: string
                minLength: 1
              html:
                type: string
                minLength: 1
              previewImage:
                type: string
                format: uri
              updatedAt:
                type: string
                minLength: 1
            required:
              - emailId
              - title
              - html
              - previewImage
              - updatedAt
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
        - pagination
      additionalProperties: false
    BrandGetResponse:
      type: object
      properties:
        brand:
          type: object
          properties:
            brandId:
              type: string
              minLength: 1
            domain:
              type: string
              minLength: 1
            status:
              type: string
              enum:
                - extracting
                - completed
                - failed
                - deleting
            ready:
              type: boolean
            progress:
              type: integer
              minimum: 0
              maximum: 100
            phase:
              type: string
            error:
              type: string
            createdAt:
              type: string
              format: date-time
            updatedAt:
              type: string
              format: date-time
          required:
            - brandId
            - domain
            - status
            - ready
          additionalProperties: false
        identity:
          type: object
          properties:
            brandName:
              type: string
            description:
              type: string
            tagline:
              type: string
            contactEmail:
              type: string
            contactPhone:
              type: string
            address:
              type: string
            socialLinks:
              type: array
              items: {}
            contentLinks:
              type: array
              items: {}
          additionalProperties: {}
        emailDesign:
          type: string
        imageStyle:
          type: string
        logos:
          type: array
          items:
            type: object
            properties:
              src:
                type: string
              type:
                type: string
              theme:
                type: string
              format:
                type: string
              background:
                type: string
              width:
                type: number
              height:
                type: number
              size:
                type: number
            required:
              - src
      required:
        - brand
      additionalProperties: false
    BrandPatchRequest:
      type: object
      properties:
        identity:
          type: object
          properties:
            brandName:
              type: string
              minLength: 1
            description:
              type: string
            tagline:
              type: string
            contactEmail:
              type: string
            contactPhone:
              type: string
            address:
              type: string
          additionalProperties: false
        emailDesign:
          type: string
          maxLength: 200000
        imageStyle:
          type: string
          maxLength: 200000
      additionalProperties: false
    BrandImagesResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              url:
                type: string
              description:
                type: string
              width:
                type: number
              height:
                type: number
              aspectRatio:
                type: string
              category:
                type: string
              pageUrl:
                type: string
              prompt:
                type: string
            required:
              - url
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
        - pagination
      additionalProperties: false
    BrandsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              brandId:
                type: string
                minLength: 1
              domain:
                type: string
                minLength: 1
              status:
                type: string
                enum:
                  - extracting
                  - completed
                  - failed
                  - deleting
              ready:
                type: boolean
              progress:
                type: integer
                minimum: 0
                maximum: 100
              phase:
                type: string
              error:
                type: string
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time
            required:
              - brandId
              - domain
              - status
              - ready
            additionalProperties: false
        pagination:
          type: object
          properties:
            limit:
              type: integer
              minimum: 1
              maximum: 100
            cursor:
              type:
                - string
                - "null"
            hasMore:
              type: boolean
          required:
            - limit
            - cursor
            - hasMore
          additionalProperties: false
      required:
        - data
        - pagination
      additionalProperties: false
    BrandsCreateResponse:
      type: object
      properties:
        brand:
          type: object
          properties:
            brandId:
              type: string
              minLength: 1
            domain:
              type: string
              minLength: 1
            status:
              type: string
              enum:
                - extracting
                - completed
                - failed
                - deleting
            ready:
              type: boolean
            progress:
              type: integer
              minimum: 0
              maximum: 100
            phase:
              type: string
            error:
              type: string
            createdAt:
              type: string
              format: date-time
            updatedAt:
              type: string
              format: date-time
          required:
            - brandId
            - domain
            - status
            - ready
          additionalProperties: false
        extraction:
          type: object
          properties:
            chatId:
              type: string
              minLength: 1
            statusUrl:
              type: string
              minLength: 1
          required:
            - chatId
            - statusUrl
      required:
        - brand
        - extraction
      additionalProperties: false
    BrandsCreateRequest:
      type: object
      properties:
        url:
          type: string
          minLength: 1
          maxLength: 2048
        instructions:
          type: string
          maxLength: 4000
        includePaths:
          type: array
          items:
            type: string
            maxLength: 2048
          maxItems: 50
        excludePaths:
          type: array
          items:
            type: string
            maxLength: 2048
          maxItems: 50
        excludeSubdomains:
          type: array
          items:
            type: string
            maxLength: 253
          maxItems: 50
      required:
        - url
      additionalProperties: false
    BrandGetByIdResponse:
      type: object
      properties:
        brand:
          type: object
          properties:
            brandId:
              type: string
              minLength: 1
            domain:
              type: string
              minLength: 1
            status:
              type: string
              enum:
                - extracting
                - completed
                - failed
                - deleting
            ready:
              type: boolean
            progress:
              type: integer
              minimum: 0
              maximum: 100
            phase:
              type: string
            error:
              type: string
            createdAt:
              type: string
              format: date-time
            updatedAt:
              type: string
              format: date-time
          required:
            - brandId
            - domain
            - status
            - ready
          additionalProperties: false
      required:
        - brand
      additionalProperties: false
    ContentImageResponse:
      type: object
      properties:
        url:
          type: string
          format: uri
        prompt:
          type: string
        description:
          type: string
        warnings:
          type: array
          items:
            type: string
      required:
        - url
        - prompt
      additionalProperties: false
    ContentGenerateImageRequest:
      type: object
      properties:
        prompt:
          type: string
          minLength: 1
          maxLength: 4000
        mode:
          type: string
          enum:
            - text-to-image
            - image-editing
        aspectRatio:
          type: string
          enum:
            - 16:9
            - 3:2
            - 4:3
            - 1:1
            - 4:5
            - 2:3
            - 3:4
            - 9:16
        image1:
          type: string
          format: uri
        image2:
          type: string
          format: uri
        adCreative:
          type: object
          properties:
            brandName:
              type: string
              minLength: 1
              maxLength: 200
            headline:
              type: string
              minLength: 1
              maxLength: 200
            cta:
              type: string
              minLength: 1
              maxLength: 100
            format:
              type: string
              enum:
                - 1:1
                - 4:5
                - 9:16
                - 16:9
            archetype:
              type: string
              enum:
                - product-ui-card
                - mascot
                - flat-illustration
                - abstract-brand
                - type-led
                - photo-ui-overlay
                - conceptual-3d
                - gradient-field
                - editorial-photo
                - collage
                - isometric-blueprint
                - data-viz
            layout:
              type: string
              enum:
                - split-right
                - split-left
                - stacked-center
                - visual-first
                - type-poster
                - immersive-field
                - layered-collage
                - badge-offer
                - diagonal-stage
                - editorial-grid
            eyebrow:
              type: string
              minLength: 1
              maxLength: 80
            subjectImageUrl:
              type: string
              format: uri
            emailCanvasColor:
              type: string
              minLength: 1
              maxLength: 40
            palette:
              type: object
              properties:
                background:
                  type: string
                  minLength: 1
                accent:
                  type: string
                  minLength: 1
                headlineColor:
                  type: string
                  minLength: 1
              required:
                - background
                - accent
                - headlineColor
              additionalProperties: false
            supportingVisual:
              type: string
              maxLength: 600
            subhead:
              type: string
              maxLength: 200
          required:
            - brandName
            - headline
            - cta
            - format
            - archetype
            - palette
          additionalProperties: false
      additionalProperties: false
    ContentGifResponse:
      type: object
      properties:
        gifUrl:
          type: string
          format: uri
        videoUrl:
          type: string
          format: uri
        generatedImageUrl:
          type: string
          format: uri
        altText:
          type: string
        duration:
          type: number
        fps:
          type: number
        aspectRatio:
          type: string
        loop:
          type: boolean
      required:
        - gifUrl
      additionalProperties: false
    ContentGifRequest:
      oneOf:
        - type: object
          properties:
            from:
              type: string
              enum:
                - prompt
            prompt:
              type: string
              minLength: 1
              maxLength: 2000
            fps:
              type: integer
              minimum: 1
              maximum: 24
            aspectRatio:
              type: string
              enum:
                - 16:9
                - 9:16
                - 1:1
            loop:
              type: boolean
          required:
            - from
            - prompt
          additionalProperties: false
        - type: object
          properties:
            from:
              type: string
              enum:
                - image
            imageUrl:
              type: string
              format: uri
            prompt:
              type: string
              minLength: 1
              maxLength: 2000
            fps:
              type: integer
              minimum: 1
              maximum: 24
            aspectRatio:
              type: string
              enum:
                - 16:9
                - 9:16
                - 1:1
            loop:
              type: boolean
          required:
            - from
            - imageUrl
          additionalProperties: false
        - type: object
          properties:
            from:
              type: string
              enum:
                - video
            videoUrl:
              type: string
              format: uri
            fps:
              type: integer
              minimum: 1
              maximum: 24
            width:
              type: integer
              minimum: 16
              maximum: 2000
          required:
            - from
            - videoUrl
          additionalProperties: false
    ContentTransformResponse:
      type: object
      properties:
        url:
          type: string
          format: uri
        width:
          type: integer
          minimum: 0
        height:
          type: integer
          minimum: 0
        aspectRatio:
          type: string
        bytes:
          type: integer
          minimum: 0
        fallbackUsed:
          type: boolean
      required:
        - url
        - width
        - height
      additionalProperties: false
    ContentTransformRequest:
      oneOf:
        - type: object
          properties:
            operation:
              type: string
              enum:
                - optimize
            imageUrl:
              type: string
              format: uri
          required:
            - operation
            - imageUrl
          additionalProperties: false
        - type: object
          properties:
            operation:
              type: string
              enum:
                - resize
            imageUrl:
              type: string
              format: uri
            width:
              type: integer
              minimum: 1
              maximum: 4096
            height:
              type: integer
              minimum: 1
              maximum: 4096
            prompt:
              type: string
              maxLength: 2000
            resolution:
              type: string
              enum:
                - 1K
                - 2K
                - 4K
            outputFormat:
              type: string
              enum:
                - png
                - jpeg
                - webp
          required:
            - operation
            - imageUrl
            - width
            - height
          additionalProperties: false
        - type: object
          properties:
            operation:
              type: string
              enum:
                - remove_background
            imageUrl:
              type: string
              format: uri
          required:
            - operation
            - imageUrl
          additionalProperties: false
    ContentPngResponse:
      type: object
      properties:
        url:
          type: string
          format: uri
        width:
          type: integer
          minimum: 0
      required:
        - url
        - width
      additionalProperties: false
    ContentHtmlToPngRequest:
      type: object
      properties:
        html:
          type: string
          minLength: 1
          maxLength: 2000000
        width:
          type: integer
          minimum: 50
          maximum: 2000
        maxHeight:
          type: integer
          minimum: 50
          maximum: 20000
      required:
        - html
      additionalProperties: false
    ContentAddImageResponse:
      type: object
      properties:
        url:
          type: string
          format: uri
        width:
          type: integer
          minimum: 0
        height:
          type: integer
          minimum: 0
        aspectRatio:
          type: string
      required:
        - url
        - width
        - height
        - aspectRatio
      additionalProperties: false
    ContentAddImageBatchResponse:
      type: object
      properties:
        accepted:
          type: integer
          minimum: 0
        skipped:
          type: integer
          minimum: 0
        runId:
          type: string
      required:
        - accepted
        - skipped
      additionalProperties: false
    ContentAddImageRequest:
      oneOf:
        - type: object
          properties:
            imageUrl:
              type: string
              format: uri
          required:
            - imageUrl
          additionalProperties: false
        - type: object
          properties:
            imageUrls:
              type: array
              items:
                type: string
                format: uri
              minItems: 1
              maxItems: 100
          required:
            - imageUrls
          additionalProperties: false
    UsageGetResponse:
      type: object
      properties:
        plan:
          type: object
          properties:
            key:
              type: string
              minLength: 1
            name:
              type: string
              minLength: 1
          required:
            - key
            - name
          additionalProperties: false
        credits:
          type: object
          properties:
            limit:
              type:
                - integer
                - "null"
              minimum: 0
            used:
              type: integer
              minimum: 0
            remaining:
              type:
                - integer
                - "null"
            reserved:
              type: integer
              minimum: 0
          required:
            - limit
            - used
            - remaining
          additionalProperties: false
        emailSends:
          type: object
          properties:
            limit:
              type:
                - integer
                - "null"
              minimum: 0
            used:
              type: integer
              minimum: 0
            remaining:
              type:
                - integer
                - "null"
            reserved:
              type: integer
              minimum: 0
          required:
            - limit
            - used
            - remaining
          additionalProperties: false
        period:
          type: object
          properties:
            start:
              type:
                - string
                - "null"
              format: date-time
            end:
              type:
                - string
                - "null"
              format: date-time
          required:
            - start
            - end
          additionalProperties: false
      required:
        - plan
        - credits
        - emailSends
        - period
      additionalProperties: false
    IntegrationsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              provider:
                type: string
                enum:
                  - braze
                  - brevo
                  - clerk
                  - customerio
                  - figma
                  - slack
                  - hubspot
                  - typeform
                  - klaviyo
                  - iterable
                  - postmark
                  - onesignal
                  - mailgun
                  - sendgrid
                  - mailjet
                  - mailchimp
                  - stripe
                  - stytch
                  - supabase
                  - workos
                  - shopify
                  - revenuecat
              name:
                type: string
                minLength: 1
              category:
                type: string
                enum:
                  - data_in
                  - data_out
              connected:
                type: boolean
              comingSoon:
                type: boolean
                enum:
                  - true
            required:
              - provider
              - name
              - category
              - connected
            additionalProperties: false
      required:
        - data
      additionalProperties: false
    ApiKeysListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              keyId:
                type: string
                minLength: 1
              name:
                type: string
                minLength: 1
              keyPreview:
                type: string
                minLength: 1
              createdAt:
                type: string
                format: date-time
              lastUsedAt:
                type: string
                format: date-time
              status:
                type: string
                enum:
                  - active
                  - revoked
              brandId:
                type: string
                minLength: 1
              permissions:
                type: array
                items:
                  type: string
                  minLength: 1
            required:
              - keyId
              - name
              - keyPreview
              - createdAt
              - status
              - permissions
            additionalProperties: false
      required:
        - data
      additionalProperties: false
    ApiKeysCreateResponse:
      type: object
      properties:
        key:
          type: string
          minLength: 1
        keyId:
          type: string
          minLength: 1
        message:
          type: string
          minLength: 1
      required:
        - key
        - keyId
        - message
      additionalProperties: false
    ApiKeysCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 80
        permissions:
          type: array
          items:
            type: string
            enum:
              - all
              - contacts
              - emails
              - automations
              - transactional
              - domains
              - sends
              - audiences
              - brands
          minItems: 1
        brandId:
          type: string
          minLength: 1
          maxLength: 64
      additionalProperties: false
    ApiKeysDeleteResponse:
      type: object
      properties:
        keyId:
          type: string
          minLength: 1
        revoked:
          type: boolean
      required:
        - keyId
        - revoked
      additionalProperties: false
    HealthResponse:
      type: object
      properties:
        status:
          type: string
          enum:
            - ok
        version:
          type: string
      required:
        - status
        - version
      additionalProperties: false
    HelpResponse:
      type: object
      additionalProperties: {}
  parameters: {}
paths:
  /v1/emails:
    get:
      operationId: listEmails
      tags:
        - Emails
      summary: Get emails
      description: "Unified email-design read. Omit `emailId` to LIST the brand’s designs (newest first) under `{ data, pagination }` — each row carries `emailId`, the latest `emailVersionId`, `title`, `status`, `previewImage` (when captured), `updatedAt`, and `group` (`{ groupId, groupName }` or `null` when Ungrouped). Filter with `?status=`, `?groupId=` (`grp_…` or `ungrouped`), and the `createdAtFrom/To` + `updatedAtFrom/To` ISO-8601 windows; paginate with `limit` + `cursor`. Pass `?emailId=` to fetch ONE design — returns `{ data: [row] }` (no `pagination`), `404 EMAIL_NOT_FOUND` on an unknown / cross-brand id. Add detail-only `?include=html` (rendered HTML) and/or `?include=versions` (lean `{ version, emailVersionId }` history) — both rejected without `emailId`."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
          required: false
          name: emailId
          in: query
        - schema:
            type: string
          required: false
          name: include
          in: query
        - schema:
            type: string
            enum:
              - streaming
              - complete
              - error
          required: false
          name: status
          in: query
        - schema:
            type: string
            format: date-time
          required: false
          name: createdAtFrom
          in: query
        - schema:
            type: string
            format: date-time
          required: false
          name: createdAtTo
          in: query
        - schema:
            type: string
            format: date-time
          required: false
          name: updatedAtFrom
          in: query
        - schema:
            type: string
            format: date-time
          required: false
          name: updatedAtTo
          in: query
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Filter LIST mode to one group (`grp_…` or `ungrouped`). Ignored in detail mode.
          required: false
          description: Filter LIST mode to one group (`grp_…` or `ungrouped`). Ignored in detail mode.
          name: groupId
          in: query
        - schema:
            anyOf:
              - type: number
              - type: string
          required: false
          name: limit
          in: query
        - schema:
            type: string
            minLength: 1
            maxLength: 512
          required: false
          name: cursor
          in: query
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "A page of email designs (list mode), or `{ data: [row] }` (detail mode)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailsListResponse"
              example:
                data:
                  - emailId: eml_welcome
                    emailVersionId: emv_welcome_v3
                    title: Welcome Email
                    status: complete
                    previewImage: https://cdn.brew.new/p/eml_welcome.png
                    updatedAt: 2026-04-08T12:34:56.789Z
                    group:
                      groupId: grp_welcome
                      groupName: Welcome
                  - emailId: eml_digest
                    emailVersionId: emv_digest_v1
                    title: May product digest
                    status: complete
                    updatedAt: 2026-04-07T09:00:00.000Z
                    group: null
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: Invalid query (unknown param, bad enum, `*From` later than its `*To`, or `include` without `emailId`).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: status
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: Email design not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: &a4
                error:
                  code: EMAIL_NOT_FOUND
                  type: not_found
                  message: No email exists with id 'eml_2SmZOWV3ZQ7W5x6g3m4p'.
                  suggestion: List designs with GET /v1/emails to find a valid emailId.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: emailId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    post:
      operationId: generateEmail
      tags:
        - Emails
      summary: Generate an email design
      description: |-
        Generates a new design through the Brew email agent. Emails are pure DESIGNS in the decoupled model — no send state, no type. Sending happens later — `POST /v1/sends` delivers the design to a target (a saved audience, an inline list, or a single address) via a verified domain (or fires a one-off test with `test: true`), or a `sendEmail` node in an automation graph references the returned `emailId` + `emailVersionId`.

        Returns `201` with `{ emailId, emailVersionId, html, previewImage?, group, subjectLine? }` when a design was persisted, or `200` with `{ response }` when the agent answered in prose without writing a design. Optional `subjectLine` sets the design-default inbox subject (`POST /v1/sends` still takes an explicit per-send `subject`). Optional `targetGroupId` (`grp_…` or `ungrouped`) or `targetGroupName` (resolve-or-create) — not both; omit to land Ungrouped. Unknown `targetGroupId` → `404 EMAIL_GROUP_NOT_FOUND`. Supports `Idempotency-Key` for safe retries.
      parameters:
        - &a1
          name: Idempotency-Key
          in: header
          required: false
          description: Optional idempotency key for safe retries. Reusing the same key with the same request body returns the original response for 24 hours.
          schema:
            type: string
            minLength: 1
            maxLength: 100
          example: api-request-2026-04-08-001
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        description: Generation prompt plus optional source URLs / reference design. The brand comes from the credential (or the `X-Brand-Id` header on an organization-scoped one) and must not be passed in the body.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailGenerateRequest"
            examples:
              basic:
                summary: Generate a design from a prompt
                value:
                  prompt: Create a welcome email for new customers who joined Brew today.
              fromContent:
                summary: Synthesize one email from up to 8 source URLs
                value:
                  prompt: Summarize this month’s product updates into a newsletter.
                  contentUrls:
                    - https://example.com/blog/product-launch
      responses:
        "200":
          description: The agent answered in prose without writing a design (`{ response }`).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailGenerateTextResponse"
              example: &a3
                response: No email was generated.
        "201":
          description: "A design was persisted. Usage-metered: the actual token usage of the email agent is charged (no fixed price, so no `X-Credit-Cost` header). `emailVersionId` pins the exact version for sends + automation `sendEmail` nodes."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailGenerateGeneratedResponse"
              example: &a2
                emailId: eml_2SmZOWV3ZQ7W5x6g3m4p
                emailVersionId: emv_2SmZOWV3ZQ7W5x6g3m4p_v1
                html: <!DOCTYPE html><html><body>Welcome to Brew.</body></html>
                previewImage: https://storage.example.com/emails/eml_2SmZOWV3ZQ7W5x6g3m4p.png
                group: null
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: prompt
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: The brand bound to the API key is missing or not accessible.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: BRAND_NOT_FOUND
                  type: not_found
                  message: The requested brand was not found.
                  suggestion: Verify in the dashboard that the brand bound to this API key still exists.
                  docs: https://docs.brew.new/api-reference/api/errors
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: "The brand bound to the API key has not finished extraction — check `GET /v1/brand` for `ready: true` first."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: BRAND_NOT_READY
                  type: invalid_request
                  message: The requested brand is not ready for email generation.
                  suggestion: Wait for brand extraction to complete (GET /v1/brand → ready) before generating emails.
                  docs: https://docs.brew.new/api-reference/api/errors
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
  /v1/emails/import:
    post:
      operationId: importEmail
      tags:
        - Emails
      summary: Import an email
      description: |-
        Converts existing markup into a NEW, fully EDITABLE Brew email design on the brand canvas. Brew preserves source structure and attempts to rehost every discoverable safe public resource. If rehosting fails, a validated public URL may be retained with a warning; private, malformed, and blocked references are stripped.

        `content` is the raw markup as a STRING; `format` describes what you supply: `html` (an HTML email document or fragment), `mjml` (MJML markup), or `jsx` (React-Email JSX) — all converted into a clean, editable design. Pass `baseUrl` to resolve relative image paths. Optional `title` and `subjectLine` (the design-default inbox subject).

        FREE — no model and no credits. Conversion is a deterministic compiler, so there is no token spend to meter and no credit gate. Normal request limits still apply: 5,000,000 UTF-8 bytes, 256 remote resources, 8 concurrent fetches, 10 MB per resource, and 50 MB aggregate downloads. Optional `targetGroupId` (`grp_…` or `ungrouped`) or `targetGroupName` (resolve-or-create) — not both; omit to land Ungrouped. Unknown `targetGroupId` → `404 EMAIL_GROUP_NOT_FOUND`. Returns `201` with `{ emailId, emailVersionId, html, previewImage?, assetReport, group, subjectLine? }`.
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailImportRequest"
            examples:
              html:
                summary: Import an HTML email
                value:
                  format: html
                  title: Spring sale
                  content: <html><body><h1>Spring sale</h1><p>20% off everything.</p><img src="https://example.com/banner.png" alt="banner"></body></html>
              mjml:
                summary: Import MJML markup
                value:
                  format: mjml
                  content: <mjml><mj-body><mj-section><mj-column><mj-text>Spring sale — 20% off</mj-text></mj-column></mj-section></mj-body></mjml>
              jsx:
                summary: Import React-Email JSX
                value:
                  format: jsx
                  content: <Html><Body><Container><Heading>Welcome</Heading><Text>Thanks for joining.</Text></Container></Body></Html>
      responses:
        "201":
          description: The design was imported + persisted. Free — no model runs. `emailVersionId` pins the exact version for sends + automation nodes.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailImportResponse"
              example:
                emailId: eml_2SmZOWV3ZQ7W5x6g3m4p
                emailVersionId: emv_2SmZOWV3ZQ7W5x6g3m4p_v1
                html: <!DOCTYPE html><html><body>Welcome to Brew.</body></html>
                previewImage: https://storage.example.com/emails/eml_2SmZOWV3ZQ7W5x6g3m4p.png
                assetReport:
                  discovered: 1
                  rehosted: 1
                  retained: 0
                  stripped: 0
                  warnings: []
                group: null
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: content
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: Unknown or cross-brand `targetGroupId`. List groups with `GET /v1/email-groups`.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_GROUP_NOT_FOUND
                  type: not_found
                  message: No email group exists with id 'grp_missing'.
                  suggestion: List groups with GET /v1/email-groups. Cross-brand ids surface as 404 to avoid leaking existence.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: targetGroupId
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "413":
          description: The source or one of its resource budgets exceeds the deterministic import limits.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: PAYLOAD_TOO_LARGE
                  type: invalid_request
                  message: content must not exceed 5000000 UTF-8 bytes
                  suggestion: Reduce the payload size and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: content
        "422":
          description: The markup could not be converted into a valid email (e.g. it failed to render, or produced no usable design).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_IMPORT_FAILED
                  type: invalid_request
                  message: "The supplied markup could not be imported as an email: the content could not be rendered to a valid email."
                  suggestion: Check that `content` is valid for the declared `format` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: content
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/emails/figma:
    post:
      operationId: importFigmaDesign
      tags:
        - Emails
      summary: Import a Figma frame
      description: |-
        Deterministically converts one selected Figma frame into a new editable Brew email design. No model runs and no credits are charged.

        `figmaUrl` must be a Figma frame link containing `node-id`. The API-key brand must already have Figma connected in Brew Integrations, and that connected account must be able to read the file.

        Set `format` to `jsx` (default) for React Email JSX or `html` for rendered email HTML. The requested representation is returned in `content`; the persisted design is identified by `emailId` and `emailVersionId`. Optional `targetGroupId` (`grp_…` or `ungrouped`) or `targetGroupName` (resolve-or-create) — not both; omit to land Ungrouped. Unknown `targetGroupId` → `404 EMAIL_GROUP_NOT_FOUND`.
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FigmaToEmailRequest"
            examples:
              jsx:
                summary: Return React Email JSX
                value:
                  figmaUrl: https://www.figma.com/design/abc123/Launch-email?node-id=1-2
                  title: Launch email
                  format: jsx
              html:
                summary: Return rendered HTML
                value:
                  figmaUrl: https://www.figma.com/design/abc123/Launch-email?node-id=1-2
                  format: html
      responses:
        "201":
          description: The converted design was persisted and the requested source representation is returned in `content`.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FigmaToEmailResponse"
              example:
                emailId: eml_figma_launch
                emailVersionId: emv_figma_launch_v1
                title: Launch email
                format: jsx
                content: <Html><Body><Container><Heading>Launch day</Heading></Container></Body></Html>
                warningCount: 0
                exportedNodeCount: 2
                previewImage: https://cdn.brew.new/p/eml_figma_launch.png
                group: null
        "400":
          description: The JSON body is invalid, or the URL is not a Figma frame link containing `node-id`.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: FIGMA_URL_INVALID
                  type: invalid_request
                  message: The Figma link is missing a frame reference.
                  suggestion: In Figma, select the email frame and copy its link. The URL must include a node-id.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: figmaUrl
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The API key lacks the emails scope, or the connected Figma account cannot read the file.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              examples:
                insufficientPermission:
                  summary: API key lacks the emails scope
                  value:
                    error:
                      code: INSUFFICIENT_PERMISSIONS
                      type: authorization_error
                      message: The caller does not have the required permission.
                      suggestion: Use an API key or session with the required permission.
                      docs: https://docs.brew.new/api-reference/api/authentication
                      param: emails
                figmaAccessDenied:
                  summary: Connected Figma account cannot access the frame
                  value:
                    error:
                      code: FIGMA_ACCESS_DENIED
                      type: authorization_error
                      message: The connected Figma account cannot access that design or selected frame.
                      suggestion: Grant the connected Figma account access to the file and selected frame, then retry.
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: figmaUrl
                      details:
                        emailId: eml_figma_launch
        "404":
          description: The Figma file or selected frame no longer exists.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: FIGMA_FRAME_NOT_FOUND
                  type: not_found
                  message: Figma could not find that design or selected frame.
                  suggestion: Confirm the file and frame still exist, then copy a fresh frame link from Figma.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: figmaUrl
                  details:
                    emailId: eml_figma_launch
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: Figma is not connected for the API-key brand, or the selected frame could not be converted.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              examples:
                figmaNotConnected:
                  summary: Connect Figma for this brand
                  value:
                    error:
                      code: FIGMA_NOT_CONNECTED
                      type: invalid_request
                      message: Figma is not connected for this brand.
                      suggestion: Connect or reconnect Figma for the API key's brand in Brew Integrations, then retry.
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: figmaUrl
                conversionFailed:
                  summary: The persisted frame could not be converted
                  value:
                    error:
                      code: FIGMA_CONVERSION_FAILED
                      type: invalid_request
                      message: The Figma frame could not be converted into an email design.
                      suggestion: Confirm the frame is a self-contained email design, then retry. The partially created design is referenced by `details.emailId`.
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: figmaUrl
                      details:
                        emailId: eml_figma_launch
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: Figma is temporarily unavailable.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: FIGMA_UNAVAILABLE
                  type: service_unavailable
                  message: Figma is temporarily unavailable. Please try again.
                  suggestion: Retry after a short delay.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: figmaUrl
                  retryAfter: 2
                  details:
                    emailId: eml_figma_launch
  /v1/emails/{emailId}:
    patch:
      operationId: editEmail
      tags:
        - Emails
      summary: Edit an email design
      description: |-
        Two kinds of change, combinable in one call — at least one of `prompt` / `subjectLine` is required:

        - `prompt` — a natural-language AI edit (optionally a `emailVersionId` source pin + `contentUrls`): the Brew email agent edits the design’s current latest version (or the pinned version) and writes a new `version: "latest"` row on the same `emailId` (the previous head is demoted to a numeric historical version). USAGE-metered — the agent’s actual token spend is charged. A `subjectLine` sent alongside is applied to the new head after the edit completes.
        - `subjectLine` alone — a deterministic in-place envelope patch: no AI run, no new version, FREE. Returns the CURRENT head in the generated-email shape. `emailVersionId` requires `prompt` (a pin is meaningless for an envelope patch).
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
            example: eml_2SmZOWV3ZQ7W5x6g3m4p
          required: true
          description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
          name: emailId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        description: A natural-language `prompt` edit (optional `emailVersionId` source pin, optional `contentUrls`) and/or a `subjectLine` to set on the design — at least one of `prompt` / `subjectLine`. Identity lives on the path.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailEditRequest"
            examples:
              aiEdit:
                summary: AI prompt edit
                value:
                  prompt: Tighten the headline and replace the CTA copy with "Get started today".
              subjectOnly:
                summary: Set the subject line (no AI run, free)
                value:
                  subjectLine: Your September product roundup
              editWithSubject:
                summary: AI edit + set the subject line
                value:
                  prompt: Swap the hero image for the fall campaign shot.
                  subjectLine: Fall arrivals are here
      responses:
        "200":
          description: The edited design (a `prompt` edit writes a new `latest` version row and is USAGE-metered), the current head (a `subjectLine`-only patch — no new version, free), or a text response if the agent returned prose instead of a design.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailGenerateResponse"
              examples:
                generated:
                  summary: Generated design
                  value: *a2
                textOnly:
                  summary: Text response
                  value: *a3
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: prompt
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: The design (or the pinned `emailVersionId`) does not exist in the API-key brand.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              examples:
                emailNotFound:
                  summary: Unknown emailId
                  value:
                    error:
                      code: EMAIL_NOT_FOUND
                      type: not_found
                      message: No email exists with id 'eml_x'.
                      suggestion: List designs with GET /v1/emails.
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: emailId
                versionNotFound:
                  summary: Pinned emailVersionId does not belong to this design
                  value:
                    error:
                      code: EMAIL_VERSION_NOT_FOUND
                      type: not_found
                      message: Email 'eml_x' has no version 'emv_other'.
                      suggestion: List versions with GET /v1/emails?emailId=&include=versions.
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: emailVersionId
        "409":
          description: The design is currently being generated and cannot be edited until it completes.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_IN_PROGRESS
                  type: conflict
                  message: Email 'eml_x' is currently being generated and cannot be edited until it completes.
                  suggestion: Wait a few seconds and retry. Streaming emails finalize automatically.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: emailId
        "422":
          description: The brand has not finished extraction.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: BRAND_NOT_READY
                  type: invalid_request
                  message: The requested brand is not ready for email generation.
                  suggestion: Wait for brand extraction to complete before editing emails.
                  docs: https://docs.brew.new/api-reference/api/errors
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
    delete:
      operationId: deleteEmail
      tags:
        - Emails
      summary: Delete an email design
      description: "Hard-deletes every version of the design. Idempotent — a miss resolves with `deleted: false` plus a `reason` instead of a 404: `already_deleted` (this id was hard-deleted earlier; `deletedAt` carries when) or `not_found` (no such design on this brand, including cross-brand ids). An `already_deleted` response means the design is gone — do not retry."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
            example: eml_2SmZOWV3ZQ7W5x6g3m4p
          required: true
          description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
          name: emailId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Deleted (or already gone — see `reason`).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailsDeleteResponse"
              example:
                emailId: eml_welcome
                deleted: true
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/emails/{emailId}/clone:
    post:
      operationId: cloneEmail
      tags:
        - Emails
      summary: Clone an email design
      description: |-
        Creates a NEW design by copying the persisted source snapshot exactly. This is a deterministic database fork: it does not invoke an AI agent, reinterpret markup, re-host assets, or regenerate the preview.

        Omit `emailVersionId` to clone the current latest row, or pass a version id from `GET /v1/emails?emailId=<id>&include=versions` to clone that exact historical snapshot. Optional `targetGroupId` (`grp_…` or `ungrouped`) or `targetGroupName` (resolve-or-create) — not both; omit to inherit the source group. Unknown `targetGroupId` → `404 EMAIL_GROUP_NOT_FOUND`. The clone receives fresh design/version ids and a `Copy of …` title while JSX, rendered HTML, and the preview image remain identical.
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
            example: eml_2SmZOWV3ZQ7W5x6g3m4p
          required: true
          description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
          name: emailId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: false
        description: Optional exact source-version pin. Omit the body or send an empty object to clone latest.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailCloneRequest"
            examples:
              latest:
                summary: Clone latest
                value: {}
              pinned:
                summary: Clone an exact version
                value:
                  emailVersionId: emv_welcome_v4
      responses:
        "201":
          description: Exact clone created. The response carries the clone’s new ids plus the unchanged rendered HTML and preview.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailGenerateGeneratedResponse"
              example: *a2
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: emailVersionId
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: The source design or requested source version does not exist in the API-key brand.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_NOT_FOUND
                  type: not_found
                  message: No email exists with id 'eml_x'.
                  suggestion: List designs with GET /v1/emails.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: emailId
        "409":
          description: The source is still generating, or the idempotency key was reused with a different payload.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              examples:
                sourceInProgress:
                  summary: Source is still generating
                  value:
                    error:
                      code: EMAIL_IN_PROGRESS
                      type: conflict
                      message: Email 'eml_x' is currently being generated and cannot be cloned until it completes.
                      suggestion: Wait a few seconds and retry. Streaming emails finalize automatically.
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: emailId
                idempotencyConflict:
                  summary: Idempotency key reused with another payload
                  value:
                    error:
                      code: IDEMPOTENCY_CONFLICT
                      type: conflict
                      message: The same idempotency key was reused with a different request payload.
                      suggestion: Reuse the original payload or send a new idempotency key.
                      docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: The source design failed to generate.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_NOT_READY
                  type: invalid_request
                  message: Email 'eml_x' failed to generate and cannot be cloned.
                  suggestion: Regenerate the source email, then clone the completed design.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: emailId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/emails/{emailId}/restore:
    post:
      operationId: restoreEmailVersion
      tags:
        - Emails
      summary: Restore a historical version
      description: "Non-destructive restore: clones the numbered version into a NEW `latest` row (demoting the current head) and returns the same generated-email shape as an edit, including the fresh `emailVersionId`."
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
            example: eml_2SmZOWV3ZQ7W5x6g3m4p
          required: true
          description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
          name: emailId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailRestoreRequest"
            example:
              version: 2
      responses:
        "200":
          description: Restored — a new `latest` version row was written.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailGenerateResponse"
              example: *a2
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: version
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: The design or the requested version was not found.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_VERSION_NOT_FOUND
                  type: not_found
                  message: Email 'eml_welcome' has no version 5.
                  suggestion: List versions with GET /v1/emails?emailId=&include=versions.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: version
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/emails/{emailId}/export:
    post:
      operationId: exportEmailDesign
      tags:
        - Emails
      summary: Export a design to an ESP
      description: "Export a finished email DESIGN to a connected third-party ESP (Klaviyo, Mailchimp, HubSpot, Braze, Iterable, Postmark, OneSignal, SendGrid, Mailgun) as a reusable TEMPLATE. This is NOT a Brew send — it creates a template in the destination platform and does NOT deliver to recipients, and is unrelated to Brew sending domains or audiences. The `provider` must already be connected for the brand (connect ESPs in the Brew app). The exported HTML is automatically made ESP-portable. Pass `dryRun: true` (alias `dry_run`) to validate the design, brand ownership, and ESP connection without creating a template. Free (no credits)."
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
            example: eml_2SmZOWV3ZQ7W5x6g3m4p
          required: true
          description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
          name: emailId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailExportRequest"
            example:
              provider: klaviyo
              templateName: Welcome — Brew export
      responses:
        "200":
          description: Dry run — the design + ESP connection were validated without creating a template.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailExportResponse"
              example:
                emailId: eml_2SmZOWV3ZQ7W5x6g3m4p
                provider: klaviyo
                providerName: Klaviyo
                templateName: Welcome — Brew export
                dryRun: true
        "201":
          description: The design was exported to the ESP as a new template.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailExportResponse"
              example:
                emailId: eml_2SmZOWV3ZQ7W5x6g3m4p
                provider: klaviyo
                providerName: Klaviyo
                templateName: Welcome — Brew export
                templateId: Ab3Kd9
                dryRun: false
        "400":
          description: The requested ESP is not connected for this brand.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTEGRATION_NOT_CONNECTED
                  type: invalid_request
                  message: Klaviyo isn't connected for this brand. Connect it on the Integrations page, then export.
                  suggestion: Connect Klaviyo on the Integrations page, then retry the export.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: provider
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: Email design not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a4
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "502":
          description: The ESP rejected the export or is temporarily unavailable.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EXPORT_PROVIDER_ERROR
                  type: service_unavailable
                  message: Klaviyo rejected the template export.
                  suggestion: Check the connection in Klaviyo and retry. Reconnect it if authorization has expired.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/emails/{emailId}/accessibility-audit:
    post:
      operationId: auditEmailAccessibility
      tags:
        - Emails
      summary: Accessibility audit
      description: "Audit the email’s latest rendered HTML for accessibility issues against WCAG 2.1 (missing alt text, non-descriptive links, low text contrast, tiny fonts, missing `lang`, empty headings). Returns a `score` (0–100), a `summary`, and a list of `issues` with their WCAG criterion. FIXED cost: 5 credits (`X-Credit-Cost: 5`), charged ONLY on success — if the audit cannot complete in time, the call returns a retryable `503` and is NOT billed."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
            example: eml_2SmZOWV3ZQ7W5x6g3m4p
          required: true
          description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
          name: emailId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: The audit result.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailAccessibilityAuditResponse"
              example:
                score: 90
                summary:
                  errors: 1
                  warnings: 0
                issues:
                  - rule: img-alt
                    severity: error
                    wcag: 1.1.1
                    message: Image is missing an alt attribute. Add descriptive alt text, or alt="" if it is purely decorative.
                    element: <img src="https://cdn.brew.new/hero.png">
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: No email exists with that id (cross-brand ids surface as 404).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_NOT_FOUND
                  type: not_found
                  message: No email exists with id 'eml_welcome'.
                  suggestion: Verify the emailId via GET /v1/emails.
                  docs: https://docs.brew.new/api-reference/api/errors
        "422":
          description: The email has no rendered HTML yet (still generating).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: CONTENT_OPERATION_FAILED
                  type: invalid_request
                  message: "accessibility-audit failed: the email has no rendered HTML yet."
                  suggestion: Poll GET /v1/emails?emailId= until status is complete, then retry.
                  docs: https://docs.brew.new/api-reference/api/errors
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
  /v1/emails/{emailId}/client-previews:
    post:
      operationId: previewEmailAcrossClients
      tags:
        - Emails
      summary: Preview across clients & devices
      description: |-
        Render the design’s latest version across REAL email clients & devices — Gmail, Outlook, Apple Mail, iOS (with dark-mode variants), plus Yahoo — and return a screenshot per client rehosted on the Brew CDN. See exactly how the email looks in a specific inbox before sending.

        Pass `clients` (ids from the supported catalogue) to target specific inboxes/devices, or send `{}` for a popular default spread. Rendering is async: this is a single bounded call, so any clients still rendering when the window elapses come back in `pending` (`status: "partial"`) — call again to retry them.

        FIXED cost: 10 credits, charged (`X-Credit-Cost: 10`) ONLY when at least one client renders. If ZERO clients finish in time (or the preview service is temporarily unavailable), the call returns a retryable `503` and is NOT billed.
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
            example: eml_2SmZOWV3ZQ7W5x6g3m4p
          required: true
          description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
          name: emailId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailClientPreviewRequest"
            examples:
              default:
                summary: Popular default spread
                value: {}
              specific:
                summary: Target specific inboxes/devices
                value:
                  clients:
                    - gmailcom-lm_chrcurrent_win10
                    - outlook2021_win11_lm_dt
                    - iphone16_18
      responses:
        "200":
          description: 'Per-client screenshots. `ready` clients carry a rehosted `imageUrl`; clients still rendering are listed in `pending` with `status: "processing"`.'
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailClientPreviewResponse"
              example:
                emailId: eml_welcome
                status: partial
                previews:
                  - id: gmailcom-lm_chrcurrent_win10
                    label: Gmail (Web)
                    category: gmail
                    os: Web
                    dark: false
                    status: ready
                    imageUrl: https://cdn.brew.new/email-preview/eml_welcome/gmailcom-lm_chrcurrent_win10-abc.png
                  - id: outlook2021_win11_lm_dt
                    label: Outlook 2021 (Windows)
                    category: outlook
                    os: Windows
                    dark: false
                    status: processing
                    imageUrl: null
                pending:
                  - outlook2021_win11_lm_dt
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: No email exists with that id (cross-brand ids surface as 404).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_NOT_FOUND
                  type: not_found
                  message: No email exists with id 'eml_welcome'.
                  suggestion: Verify the emailId via GET /v1/emails.
                  docs: https://docs.brew.new/api-reference/api/errors
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: The email has no rendered HTML yet, or no supported clients were requested.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: CONTENT_OPERATION_FAILED
                  type: invalid_request
                  message: "The client-preview operation could not be completed: the email has no rendered HTML yet (it may still be generating)."
                  suggestion: Poll GET /v1/emails?emailId= until status is complete, then retry.
                  docs: https://docs.brew.new/api-reference/api/errors
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: RETRYABLE. Either no client finished rendering within the time limit (or the preview service is temporarily unavailable) — in which case you are NOT billed — or the credit balance could not be verified (fail-closed rather than doing unmeterable paid work).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: The email preview is still rendering — no client finished within the time limit.
                  suggestion: Retry in a few seconds. You are not charged when no preview is produced.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/emails/{emailId}/inbox-placement-tests:
    post:
      operationId: createInboxPlacementTest
      tags:
        - Emails
      summary: Run an inbox placement test
      description: |-
        Test where the design’s latest version LANDS — inbox vs spam vs missing — across real mailbox providers (Gmail, Outlook, Yahoo, Apple, …). Brew provisions a Mailgun seed list and sends the email to the seed addresses through your REAL send pipeline on a VERIFIED sending `domainId`, so the result reflects that domain’s true deliverability plus SPF/DKIM/DMARC.

        Returns immediately with a `testId` and `status: "collecting"`. Results accrue over a few minutes — poll `GET /v1/emails/{emailId}/inbox-placement-tests?testId=` until `status` is `completed`.

        This performs a real (small) send to the seeds IN ADDITION to the FIXED 10-credit test fee (`X-Credit-Cost: 10`), charged only on a 2xx. Requires a verified sending domain.
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
            example: eml_2SmZOWV3ZQ7W5x6g3m4p
          required: true
          description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
          name: emailId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailInboxPlacementRequest"
            examples:
              default:
                summary: Test a verified domain across all providers
                value:
                  domainId: k57e9m3q1w8r
              targeted:
                summary: Restrict to specific providers + a custom subject
                value:
                  domainId: k57e9m3q1w8r
                  subject: March newsletter
                  providers:
                    - gmail.com
                    - outlook.com
                    - yahoo.com
      responses:
        "202":
          description: The test was created and the seed send is in flight. Poll the GET endpoint for results.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailInboxPlacementTest"
              example:
                testId: ibp_2f1c9d8a-4e77-4b0e-9a1c-6d5e2f0b7c31
                emailId: eml_welcome
                status: collecting
                domainId: k57e9m3q1w8r
                seedCount: 42
                results: null
                createdAt: 2026-07-13T17:00:06.675Z
                updatedAt: 2026-07-13T17:00:06.675Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: No email exists with that id, or the domain is unknown (cross-brand ids surface as 404).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_NOT_FOUND
                  type: not_found
                  message: No email exists with id 'eml_welcome'.
                  suggestion: Verify the emailId via GET /v1/emails.
                  docs: https://docs.brew.new/api-reference/api/errors
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
    get:
      operationId: getInboxPlacementResults
      tags:
        - Emails
      summary: Get inbox placement results
      description: "With `testId`: the current status + placement of ONE test — while `status` is `collecting`, this live-refreshes from the provider (re-poll every ~30s until `completed`) and returns per-provider inbox/spam/missing tallies with folder/tab `categories` and ACTUAL `folders` (e.g. Gmail Promotions, Yahoo bulk, gmx spamverdacht), each provider's OWN SPF/DKIM/DMARC verdicts (`byProvider[].authentication`), Microsoft's filter telemetry (`microsoftFilter` — SCL >= 5 lands in Junk), a spoofing check (`spoofingDetected`), header checks (`headers` — one-click unsubscribe, plain-text part), a `spamFilter` content verdict with the triggered rules, and a `diagnosis` array of per-provider findings with concrete remediation. WITHOUT `testId`: lists the design's recent tests (lean rows, persisted snapshots — poll a `testId` to refresh) for comparing subject/preview/version variants side by side. FREE."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
            example: eml_2SmZOWV3ZQ7W5x6g3m4p
          required: true
          description: Design id returned by `POST /v1/emails` and listed by `GET /v1/emails`.
          name: emailId
          in: path
        - schema:
            type: string
            minLength: 1
            maxLength: 80
            description: The test id returned by the create endpoint; omit to list the design's recent tests.
            example: ibp_2f1c9d8a-4e77-4b0e-9a1c-6d5e2f0b7c31
          required: false
          description: The test id returned by the create endpoint; omit to list the design's recent tests.
          name: testId
          in: query
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "With `testId`: the test resource. Without: `{ data: [lean test rows] }`."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailInboxPlacementGetResponse"
              example:
                testId: ibp_2f1c9d8a-4e77-4b0e-9a1c-6d5e2f0b7c31
                emailId: eml_welcome
                status: completed
                domainId: k57e9m3q1w8r
                seedCount: 42
                results:
                  overall:
                    provider: all
                    total: 42
                    inbox: 38
                    spam: 3
                    missing: 1
                    pending: 0
                    categories:
                      inbox: 34
                      promotions: 4
                      spam: 3
                  byProvider:
                    - provider: gmail.com
                      total: 4
                      inbox: 4
                      spam: 0
                      missing: 0
                      pending: 0
                      categories:
                        inbox: 3
                        promotions: 1
                  authentication:
                    spf: pass
                    dkim: pass
                    dmarc: pass
                  spamFilter:
                    flagged: false
                    score: -0.2
                    threshold: 5
                    rules:
                      - name: DKIM_SIGNED
                        score: 0.1
                        description: Message has a DKIM signature
                createdAt: 2026-07-13T17:00:06.675Z
                updatedAt: 2026-07-13T17:00:06.675Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: No test exists with that id for this email (cross-brand ids surface as 404).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_NOT_FOUND
                  type: not_found
                  message: No email exists with id 'eml_welcome'.
                  suggestion: Verify the testId returned by the create endpoint.
                  docs: https://docs.brew.new/api-reference/api/errors
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/email-groups:
    get:
      operationId: listEmailGroups
      tags:
        - Emails
      summary: List email groups
      description: 'Unified group read. Omit `groupId` to LIST the brand’s folders under `{ data, pagination }`. Named groups use `grp_*` ids. Ungrouped is always included as `{ groupId: "ungrouped", groupName: "Ungrouped" }`. `emailCount` is capped at 100. Pass `?groupId=` to fetch ONE row as `{ data: [row] }` (no `pagination`), `404 EMAIL_GROUP_NOT_FOUND` on an unknown / cross-brand id. Filter designs in a group with `GET /v1/emails?groupId=`.'
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Named group id (`grp_…`), or `ungrouped` on reads. Writes reject Ungrouped sentinels.
          required: false
          description: Named group id (`grp_…`), or `ungrouped` on reads. Writes reject Ungrouped sentinels.
          name: groupId
          in: query
        - schema:
            anyOf:
              - type: number
              - type: string
          required: false
          name: limit
          in: query
        - schema:
            type: string
            minLength: 1
            maxLength: 512
          required: false
          name: cursor
          in: query
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "A page of email groups (list mode), or `{ data: [row] }` (detail mode)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailGroupsListResponse"
              example:
                data:
                  - groupId: grp_welcome
                    groupName: Welcome
                    emailCount: 3
                  - groupId: ungrouped
                    groupName: Ungrouped
                    emailCount: 12
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: Invalid query (unknown param, bad pagination, or a non-public Ungrouped sentinel).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: groupId
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: Email group not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: &a5
                error:
                  code: EMAIL_GROUP_NOT_FOUND
                  type: not_found
                  message: The requested email group 'grp_xxx' was not found.
                  suggestion: List groups with GET /v1/email-groups.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: groupId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    post:
      operationId: createEmailGroup
      tags:
        - Emails
      summary: Create an email group
      description: "Creates a named email folder. Returns `201` with `{ groupId, groupName, emailCount: 0 }`. Reserved names (`Ungrouped` / `ungrouped` / `__ungrouped__`) are `400`. Duplicate names are `409 EMAIL_GROUP_NAME_CONFLICT`. Pass the returned `groupId` as `targetGroupId` on create/import/clone."
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailGroupCreateRequest"
            example:
              name: Welcome
      responses:
        "201":
          description: Created.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailGroupSummary"
              example:
                groupId: grp_welcome
                groupName: Welcome
                emailCount: 0
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: name
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "409":
          description: A group with this name already exists, or the idempotency key was reused with a different body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_GROUP_NAME_CONFLICT
                  type: conflict
                  message: A group named 'Welcome' already exists in this brand.
                  suggestion: Pick a different name, or rename the existing group.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: name
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/email-groups/{groupId}:
    patch:
      operationId: updateEmailGroup
      tags:
        - Emails
      summary: Rename an email group
      description: Renames a named folder. Ungrouped cannot be renamed (`400`). Unknown / cross-brand ids are `404`. Duplicate names are `409 EMAIL_GROUP_NAME_CONFLICT`.
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Named group id (`grp_*`) returned by `POST /v1/email-groups` and listed by `GET /v1/email-groups`. Ungrouped is not a writable id.
            example: grp_welcome
          required: true
          description: Named group id (`grp_*`) returned by `POST /v1/email-groups` and listed by `GET /v1/email-groups`. Ungrouped is not a writable id.
          name: groupId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailGroupPatchRequest"
            example:
              name: Welcome series
      responses:
        "200":
          description: Updated.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailGroupSummary"
              example:
                groupId: grp_welcome
                groupName: Welcome series
                emailCount: 3
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: name
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: Email group not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a5
        "409":
          description: A group with this name already exists.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_GROUP_NAME_CONFLICT
                  type: conflict
                  message: A group named 'Welcome series' already exists in this brand.
                  suggestion: Pick a different name, or rename the existing group.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: name
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    delete:
      operationId: deleteEmailGroup
      tags:
        - Emails
      summary: Delete an email group
      description: "Deletes a named folder. Member emails move to Ungrouped. Ungrouped cannot be deleted (`400`). Idempotent — an unknown / cross-brand id resolves with `{ deleted: false }`."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Named group id (`grp_*`) returned by `POST /v1/email-groups` and listed by `GET /v1/email-groups`. Ungrouped is not a writable id.
            example: grp_welcome
          required: true
          description: Named group id (`grp_*`) returned by `POST /v1/email-groups` and listed by `GET /v1/email-groups`. Ungrouped is not a writable id.
          name: groupId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Deleted (or already gone).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailGroupDeleteResponse"
              example:
                groupId: grp_welcome
                deleted: true
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: groupId
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/analytics/sends:
    get:
      operationId: listSends
      tags:
        - Analytics
      summary: Get email sends
      description: "Unified send read. A send is the unit of delivery + analytics: one design delivered to a target (audience, inline list, or single address) via one domain. Default LIST is campaign-only. Filter object-fired transactional rows with `?kind=transactional` and/or `?transactionId=`. Leftover `?messageClass=` still filters campaign-era rows. Omit `sendId` to LIST newest first under `{ data, pagination }`; also filter with `?status=`, `?emailId=`, or the `from`/`to` ISO-8601 window. Pass `?sendId=` to fetch ONE — returns `{ data: [row] }` (no `pagination`), `404 SEND_NOT_FOUND` on an unknown / cross-brand id; add `?include=events` (detail only) for a bounded first page of the send’s analytics events. `sendId` and `emailId` are mutually exclusive."
      parameters:
        - name: sendId
          in: query
          required: false
          description: "Fetch a single send by id (detail mode → `{ data: [row] }`). Omit to list."
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: emailId
          in: query
          required: false
          description: List mode — narrow to one design’s sends. Mutually exclusive with `sendId`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: include
          in: query
          required: false
          description: "Detail-only expansion: `events` inlines a bounded first page of the send’s analytics events. Rejected without `sendId`."
          schema:
            type: string
            enum:
              - events
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - scheduled
              - queued
              - sending
              - paused
              - sent
              - partially_sent
              - failed
              - canceled
        - name: messageClass
          in: query
          required: false
          description: Admission snapshot on leftover campaign-era rows (`marketing` | `transactional`). Prefer `kind` / `transactionId` for object-fired transactional sends. Absent stamps match as marketing.
          schema:
            type: string
            enum:
              - marketing
              - transactional
        - name: kind
          in: query
          required: false
          description: "List `campaign` (default) or `transactional` fires. Object-fired rows use `kind: transactional` and carry `transactionId`."
          schema:
            type: string
            enum:
              - campaign
              - transactional
        - name: transactionId
          in: query
          required: false
          description: List fires for one transactional email object (`txn_…`). Implies transactional rows.
          schema:
            type: string
            minLength: 1
            maxLength: 128
        - name: from
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - &a7
          name: limit
          in: query
          required: false
          description: Page size (1–100). Defaults to 100.
          schema:
            type: integer
            minimum: 1
            maximum: 100
          example: 50
        - &a8
          name: cursor
          in: query
          required: false
          description: Opaque pagination cursor echoed from the previous page’s `pagination.cursor`. Omit for the first page.
          schema:
            type: string
            minLength: 1
            maxLength: 512
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "A page of sends (list mode), or `{ data: [row] }` (detail mode; `events[]` present when `?include=events`)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SendsListResponse"
              example:
                data:
                  - sendId: snd_8fK2mQ4p
                    kind: campaign
                    messageClass: marketing
                    emailId: eml_welcome
                    emailVersionId: emv_welcome_v3
                    status: sent
                    audienceId: aud_subscribers
                    audienceName: Subscribers
                    runId: wrun_abc
                    startedAt: 2026-04-08T12:00:05.000Z
                    completedAt: 2026-04-08T12:34:56.000Z
                    stats:
                      sent: 1200
                      delivered: 1180
                      opened: 540
                      clicked: 96
                      bounced: 20
                      complained: 1
                      unsubscribed: 4
                    createdAt: 2026-04-08T12:00:00.000Z
                    updatedAt: 2026-04-08T12:34:56.000Z
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: status
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: Send not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: &a6
                error:
                  code: SEND_NOT_FOUND
                  type: not_found
                  message: No send was found with id 'snd_xxx'.
                  suggestion: List sends with GET /v1/analytics/sends, or start one with POST /v1/sends.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: sendId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/sends:
    post:
      operationId: createSend
      tags:
        - Emails
      summary: Send an email
      description: |-
        Sends an email design. Polymorphic on `test` / `transactionId`:

        - **`test: true`** → a synchronous one-off TEST delivery of the design’s current (or pinned) body to a single address, with a `[TEST]` subject prefix. Sends from the Brew default sender unless a verified org-owned `domainId` is supplied (`fromEmail`/`senderName` customize it; an unverified/foreign domain is rejected, never downgraded). Optional `variables` supply example values for `{{ var | fallback }}` merge tags — a value wins over the declared fallback. Targets one `to` address and never creates a `Send` row. Returns **`200`** `{ status: "sent", recipient }`.
        - **`transactionId`** → fire a reusable transactional email object. Domain and design are locked on the object; `to` (1–50) is required; optional `payload` supplies merge-tag values. Optional envelope overrides: `replyTo`, `senderName`, `fromEmail`, `subject`, `previewText`. Creates a `sends` row with `kind: transactional`. Returns **`202`** `{ sendId, runId }`. Prefer this over leftover inline `emailId` + `domainId` + `to` on a transactional domain.
        - **default / `test: false`** → a campaign send combining the design (`emailId`, optionally pinned to `emailVersionId`), a verified `domainId`, and a target — a saved `audienceId` OR inline `to` (a single email or an array, max 50) — into one delivery event. The same design can be sent unlimited times; every call mints a new send. Returns **`202`** `{ sendId, runId }` — poll via `GET /v1/analytics/sends?sendId=`.

        Campaign target — provide EXACTLY ONE of `audienceId` or `to`. Inline recipients face the same unsubscribe/suppression gate and per-recipient quota as audience sends. For per-recipient event-driven delivery, publish an automation and fire its trigger (`POST /v1/automations/triggers/{triggerEventId}/fire`).

        Brand scoping: resources (`emailId`, `domainId`, `audienceId`) living in a different brand surface as `404` so the API never confirms cross-brand existence.
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SendEmailRequest"
            examples:
              test:
                summary: One-off test to a single address (sync 200)
                value:
                  test: true
                  emailId: eml_welcome
                  subject: Welcome to Brew
                  to: qa@acme.com
              testVerifiedDomain:
                summary: Test from your verified domain with example merge-tag values
                value:
                  test: true
                  emailId: eml_welcome
                  subject: Welcome {{ firstName | there }}
                  to: qa@acme.com
                  domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                  senderName: Vanessa
                  variables:
                    firstName: Sarah
              now:
                summary: Send the latest version to an audience now
                value:
                  emailId: eml_welcome
                  domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                  subject: Welcome to Brew
                  audienceId: aud_subscribers
              scheduledPinned:
                summary: Schedule a pinned version for later
                value:
                  emailId: eml_welcome
                  emailVersionId: emv_welcome_v2
                  domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                  subject: Welcome to Brew
                  previewText: Get started in 2 minutes.
                  audienceId: aud_subscribers
                  scheduledAt: 2099-01-01T00:00:00.000Z
              inline:
                summary: Send to inline recipients
                value:
                  emailId: eml_welcome
                  domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                  subject: Welcome to Brew
                  to:
                    - founder@acme.com
                    - design@acme.com
              transactional:
                summary: Fire a transactional email by transactionId
                value:
                  transactionId: txn_8fK2mQ4pLx
                  to: customer@acme.com
                  payload:
                    orderId: "1234"
                    firstName: Ada
              transactionalNested:
                summary: Fire a Liquid-templated transactional email with nested payload data
                value:
                  transactionId: txn_8fK2mQ4pLx
                  to: customer@acme.com
                  payload:
                    projects:
                      - project_name: Q3 Consolidation
                        mappings:
                          - quickbooks_account:
                              entity_name: FRC
                              number: "1218"
                              name: Investment Account
                            consolidation_account:
                              number: null
                              name: Other Assets
      responses:
        "200":
          description: "The TEST send (`test: true`) was delivered synchronously to the single recipient."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SendEmailTestResponse"
              example:
                status: sent
                recipient: qa@acme.com
        "202":
          description: The campaign send was accepted, queued or scheduled.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SendsPostResponse"
              example:
                status: queued
                sendId: snd_8fK2mQ4p
                runId: wrun_abc
        "400":
          description: Invalid body — missing required field (`emailId`, `domainId`, `subject`), neither or both of `audienceId`/`to`, more than 50 inline `to` addresses, a past `scheduledAt`, or an unknown key.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: audienceId
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `sends` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: sends
        "404":
          description: The referenced email, domain, or audience was not found in the API-key brand.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EMAIL_NOT_FOUND
                  type: not_found
                  message: The requested email 'eml_x' was not found.
                  suggestion: List designs with GET /v1/emails.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: emailId
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: The referenced resource exists but is not ready.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              examples:
                domainNotReady:
                  summary: Domain not verified
                  value:
                    error:
                      code: DOMAIN_NOT_READY
                      type: invalid_request
                      message: The requested domain 'dom_x' is not verified for sending.
                      suggestion: Verify the domain with POST /v1/domains/{domainId}/verify, or pick a sendable one from GET /v1/domains?sendableOnly=true.
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: domainId
                emailNotReady:
                  summary: Design still generating
                  value:
                    error:
                      code: EMAIL_NOT_READY
                      type: invalid_request
                      message: The requested email 'eml_x' is not ready to send.
                      suggestion: 'Wait for generation to finish (GET /v1/emails?emailId= → status: "complete").'
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: emailId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/sends/{sendId}/cancel:
    post:
      operationId: cancelSend
      tags:
        - Emails
      summary: Cancel a send
      description: "Cancels a scheduled or queued send before it goes out, or STOPS any in-flight campaign send. A campaign in `sending` or `paused` is canceled the same way the in-app Stop button does it: the remaining recipients are never delivered while already-sent ones stay sent (every shape re-checks liveness at regular points mid-flight — smart per time bucket, gradual and plain blast at bounded chunk intervals — so a small tail may still deliver after the cancel lands). Idempotent — a send already `canceled` returns `200`. A send already `sent` or `failed`, or a non-campaign (automation) send, returns `409 SEND_NOT_CANCELLABLE`. Brand-scoped: an unknown / cross-brand `sendId` is `404`."
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Send id returned by `POST /v1/sends`.
            example: snd_8fK2mQ4p
          required: true
          description: Send id returned by `POST /v1/sends`.
          name: sendId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: The send is canceled (or was already canceled).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SendCancelResponse"
              example:
                sendId: snd_8fK2mQ4p
                status: canceled
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `sends` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: sends
        "404":
          description: Send not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a6
        "409":
          description: The send is past the point of cancellation (terminal `sent` / `failed`, or a non-campaign send).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SEND_NOT_CANCELLABLE
                  type: conflict
                  message: Send 'snd_x' is 'sent' and can no longer be canceled — only campaign sends that are 'scheduled', 'queued', 'sending', or 'paused' can be canceled.
                  suggestion: Check the send status via GET /v1/analytics/sends?sendId=… before canceling.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: sendId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/sends/{sendId}/pause:
    post:
      operationId: pauseSend
      tags:
        - Emails
      summary: Pause a gradual send
      description: "Manually pauses an in-flight GRADUAL (domain-warmup) send. The delivering workflow parks the current day’s remaining tranche at its next gate poll (≤120s) and holds until `POST /v1/sends/{sendId}/resume` (or a cancel). A send that is not a `sending` gradual send returns `409 SEND_NOT_PAUSABLE`. Brand-scoped: an unknown / cross-brand `sendId` is `404`."
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Send id returned by `POST /v1/sends`.
            example: snd_8fK2mQ4p
          required: true
          description: Send id returned by `POST /v1/sends`.
          name: sendId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: The send is paused.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SendPauseResponse"
              example:
                sendId: snd_8fK2mQ4p
                status: paused
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `sends` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: sends
        "404":
          description: Send not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a6
        "409":
          description: The send is not a delivering gradual send (not gradual, or not `sending`).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SEND_NOT_PAUSABLE
                  type: conflict
                  message: Send 'snd_x' is 'paused' and cannot be paused — only a delivering ('sending') gradual send can be paused.
                  suggestion: Check the send status via GET /v1/analytics/sends?sendId=… — only a `sending` gradual send can be paused.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: sendId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/sends/{sendId}/resume:
    post:
      operationId: resumeSend
      tags:
        - Emails
      summary: Resume a paused gradual send
      description: "Resumes a manually paused GRADUAL send. The unsent tail is re-spread and later batches shift so missed intervals do not compress into a burst. A send that is not a `paused` gradual send returns `409 SEND_NOT_RESUMABLE`. Brand-scoped: an unknown / cross-brand `sendId` is `404`."
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Send id returned by `POST /v1/sends`.
            example: snd_8fK2mQ4p
          required: true
          description: Send id returned by `POST /v1/sends`.
          name: sendId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: The send is delivering again.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SendResumeResponse"
              example:
                sendId: snd_8fK2mQ4p
                status: sending
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `sends` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: sends
        "404":
          description: Send not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a6
        "409":
          description: The send is not a paused gradual send (not gradual, or not `paused`).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SEND_NOT_RESUMABLE
                  type: conflict
                  message: Send 'snd_x' is 'sending' and cannot be resumed — only a 'paused' gradual send can be resumed.
                  suggestion: Check the send status via GET /v1/analytics/sends?sendId=… — only a paused gradual send can be resumed.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: sendId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/transactional/{transactionId}:
    get:
      operationId: getTransactionalEmail
      tags:
        - Emails
      summary: Get a transactional email
      description: "Read a reusable transactional email object: locked `domainId` / `emailId` / `emailVersionId`, envelope defaults, and the merge-tag list for snippets. On Liquid-enabled workspaces the response also carries the payload contract — `variableTree` (every `trigger.*` / `customer.*` path the pinned template references, with array/object shape and fallbacks), `examplePayload` (a nested payload that fires verbatim), and `templating` (engine + parse validity). Recomputed from the pinned design on every read. Fire it with `POST /v1/sends { transactionId, to, payload? }`. Permission: `sends`. There is no `messageClass` on this object — purpose lives on the sending domain."
      parameters:
        - name: include
          in: query
          required: false
          description: "Pass `skill` to add a `skill` field to the response: a complete SKILL.md-shaped wiring brief (endpoint, auth, typed payload contract, copy-paste snippets) for a coding agent or your repo."
          schema:
            type: string
            enum:
              - skill
        - schema:
            type: string
            minLength: 1
            maxLength: 128
            description: Public transactional email id (`txn_…`) returned when the object is created.
            example: txn_8fK2mQ4pLx
          required: true
          description: Public transactional email id (`txn_…`) returned when the object is created.
          name: transactionId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: The transactional email object.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionalEmail"
              example:
                transactionId: txn_8fK2mQ4pLx
                emailId: eml_receipt
                emailVersionId: emv_receipt_v2
                domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                subject: Your receipt from Acme
                previewText: "Order #1234"
                createdAt: 2026-08-18T12:00:00.000Z
                updatedAt: 2026-08-18T12:00:00.000Z
                variables:
                  - name: orderId
                    type: string
                    fallback: null
                  - name: firstName
                    type: string
                    fallback: there
                templating:
                  engine: liquid
                  valid: true
                  errors: []
                variableTree:
                  - key: order
                    path: trigger.order
                    kind: object
                    fallback: null
                    namespace: trigger
                    children:
                      - key: total
                        path: trigger.order.total
                        kind: scalar
                        fallback: null
                        namespace: trigger
                        children: []
                examplePayload:
                  order:
                    total: example_total
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `sends` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: sends
        "404":
          description: Transactional email not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: TRANSACTIONAL_EMAIL_NOT_FOUND
                  type: not_found
                  message: No transactional email was found with id 'txn_xxx'.
                  suggestion: Create one from Email Actions → Transactional Email, then fire it with POST /v1/sends { transactionId, to }.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: transactionId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/analytics/overview:
    get:
      operationId: getAnalyticsOverview
      tags:
        - Analytics
      summary: Brand overview (totals, rates, timeseries)
      description: "Windowed brand overview — the EXACT read behind the app's /analytics metric cards + chart (same per-recipient dedup and machine-click/open exclusion rules), so API/MCP numbers can never disagree with the page. Defaults to the last 7 days. Optional filters, all of which COMPOSE freely: `source` (csv of send sources), `automationId`, `emailId`, `audienceId` (csv, ≤20), `triggerEventId` (csv, ≤10 — integration trigger-events, resolved to their wired automations), `domain` (sending domain), and `recipient` (csv of recipient rules — same grammar and name as `GET /v1/analytics/events`). A single filter is answered from pre-aggregated rollup rows; any combination (and anything with `domain` or `recipient`, neither of which has a rollup dimension) is answered by aggregating raw events instead — exact, but capped, so watch `truncated` on wide windows. Returns `{ totals, rates, buckets, granularity, timeZone, range, truncated }` — `truncated: true` means the window exceeded the scan budget; narrow the range. Requires the `emails` scope."
      parameters:
        - name: from
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - name: source
          in: query
          required: false
          description: "CSV of send sources to include (e.g. `audience,api`; valid values: audience, api, automation_manual, automation_integration, automation_custom). Composes with every other filter."
          schema:
            type: string
            minLength: 1
            maxLength: 256
        - name: automationId
          in: query
          required: false
          description: CSV of automation ids (max 20) — a single id is still valid. Composes with every other filter; one id reads a pre-aggregated rollup partition, several take the raw-event path.
          schema:
            type: string
            minLength: 1
            maxLength: 2048
        - name: emailId
          in: query
          required: false
          description: Scope to one email design. Composes with every other filter — a design used by several automations can be narrowed with `automationId`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: audienceId
          in: query
          required: false
          description: CSV of audience ids (max 20). Composes with every other filter.
          schema:
            type: string
            minLength: 1
            maxLength: 2048
        - name: triggerEventId
          in: query
          required: false
          description: CSV of integration trigger-event ids (max 10), resolved to their wired automations. Composes with every other filter.
          schema:
            type: string
            minLength: 1
            maxLength: 2048
        - name: domain
          in: query
          required: false
          description: Sending domain (`fromEmail` match). Has no rollup dimension, so requests carrying it are answered from raw events — check `truncated` on wide windows.
          schema:
            type: string
            minLength: 1
            maxLength: 255
        - name: recipient
          in: query
          required: false
          description: CSV of recipient rules (max 10) matching who RECEIVED the email — the SAME grammar and the same parameter name as `GET /v1/analytics/events`, so one filter string moves between the two and the totals here describe exactly the rows that feed lists. A full address matches exactly, `@domain` matches the domain, any other text matches as a substring; prefix `!` to exclude (e.g. `@clay.com,!ceo@clay.com`). Includes OR together; excludes always apply. Like `domain` this has no rollup dimension (stored rows aggregate ACROSS recipients), so requests carrying it are answered from raw events — check `truncated` on wide windows.
          schema:
            type: string
            minLength: 1
            maxLength: 2048
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Brand-wide totals, rates, and a zero-filled timeseries for the window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AnalyticsOverviewResponse"
              example:
                totals:
                  sent: 5000
                  delivered: 4920
                  opened: 2110
                  clicked: 540
                  bounced: 80
                  complained: 3
                  unsubscribed: 12
                  failed: 0
                  suppressed: 14
                  deliveryDelayed: 2
                rates:
                  deliveryRate: 0.984
                  openRate: 0.4289
                  clickRate: 0.1098
                  bounceRate: 0.016
                  complaintRate: 0.0006
                  unsubscribeRate: 0.0024
                buckets:
                  - at: 2026-04-08T00:00:00.000Z
                    sent: 5000
                    delivered: 4920
                    deliveryDelayed: 2
                    opened: 2110
                    clicked: 540
                    bounced: 80
                    complained: 3
                    failed: 0
                    suppressed: 14
                    unsubscribed: 12
                granularity: 1d
                timeZone: America/New_York
                range:
                  from: 2026-04-01T12:34:56.789Z
                  to: 2026-04-08T12:34:56.789Z
                truncated: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: from
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/analytics/campaigns:
    get:
      operationId: getCampaignAnalytics
      tags:
        - Analytics
      summary: Campaign performance
      description: "Lifetime KPIs per campaign SEND (one row per `sendId` — a design sent twice has two rows): sent / delivered / opened / clicked / bounced / complained / unsubscribed. Read-only, cursor-paginated under `{ data, pagination }`. Requires the `emails` scope. For a single send, `GET /v1/analytics/sends?sendId=` carries the same `stats`."
      parameters:
        - *a7
        - *a8
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: A page of per-send lifetime performance rows.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CampaignAnalyticsResponse"
              example:
                data:
                  - sendId: snd_8fK2mQ4p
                    emailId: eml_launch
                    title: Spring Launch
                    status: sent
                    audienceName: Subscribers
                    sentAt: 2026-04-08T12:34:56.789Z
                    stats:
                      sent: 5000
                      delivered: 4920
                      opened: 2110
                      clicked: 540
                      bounced: 80
                      complained: 3
                      unsubscribed: 12
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: limit
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/analytics/automations:
    get:
      operationId: getAutomationAnalytics
      tags:
        - Analytics
      summary: Automation performance
      description: "Windowed per-automation performance + scoped `totals` + the resolved `range`. Defaults to the last 30 days. Reflects LIVE runs only (test runs never contribute). Totals include every matching automation independently from the displayed row `limit`. Narrow with the `automationId` filter; bound the window with `from` / `to`. Check `truncated`: when true, scan budgets clipped the requested window and the metrics are partial. Requires the `automations` scope."
      parameters:
        - name: from
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - name: automationId
          in: query
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Per-automation performance + totals for the window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationAnalyticsResponse"
              example:
                data:
                  - automationId: auto_welcome
                    name: Welcome flow
                    published: true
                    triggerEventId: tri_signup
                    runs: 1200
                    completed: 1180
                    failed: 5
                    sent: 1180
                    delivered: 1150
                    opened: 690
                    clicked: 210
                    bounced: 18
                    successRate: 0.983
                    openRate: 0.6
                    clickRate: 0.182
                    clickThroughRate: 0.304
                    lastRunAt: 2026-04-08T12:34:56.789Z
                    lastRunStatus: completed
                totals:
                  runs: 1200
                  completed: 1180
                  failed: 5
                  sent: 1180
                  delivered: 1150
                  opened: 690
                  clicked: 210
                  bounced: 18
                range:
                  from: 2026-03-09T12:34:56.789Z
                  to: 2026-04-08T12:34:56.789Z
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: from
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/analytics/events:
    get:
      operationId: getEventsAnalytics
      tags:
        - Analytics
      summary: Unified events feed
      description: "Read-only window over the brand’s analytics events across domains (email, automation, trigger, inbound). Defaults to the last 7 days. Equality filters: `recipientEmail`, `eventType`, `automationId`, `sendId` (join back to `/v1/analytics/sends?sendId=`), `messageClass` (`marketing` | `transactional` — same event object; absent stamps match as marketing). Recipient rules — `recipient` (csv, ≤10): a full address matches exactly, `@domain` matches everyone on that domain, any other text matches as a substring, and a `!` prefix excludes (`recipient=@clay.com,!ceo@clay.com` = clay recipients except the CEO); includes OR together, excludes always apply. Send-object facets — `source` (csv of send sources), `audienceId` (csv, ≤20), `emailId` (design), `domain` (sending domain), `triggerEventId` (csv, ≤10 — integration trigger-events resolved to their wired automations), `messageClass`: when ANY facet or recipient rule is present the feed narrows to EMAIL events only and each row is enriched with `sendSource` + `sendContext` + `messageClass` (plus `triggerProvider`/`triggerTitle` on integration/custom-triggered rows). Overview/insights collect transactional events like any other email event. Machine/bot-classified `clicked` AND `opened` rows (scanner detonation, Apple-proxy prefetch) are EXCLUDED by default (matching `/v1/analytics/overview`); pass `includeMachineClicks=true` / `includeMachineOpens=true` to include the raw rows (audit/debug only). Cursor pagination — pass `pagination.cursor` back as `?cursor=`; loop `while (cursor !== null)`. Requires the `emails` scope."
      parameters:
        - name: from
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - name: recipientEmail
          in: query
          required: false
          schema:
            type: string
            format: email
        - name: recipient
          in: query
          required: false
          description: "CSV of recipient rules (max 10) matching who RECEIVED the email: a full address matches exactly, `@domain` matches the domain, any other text matches as a substring; prefix `!` to exclude (e.g. `@clay.com,!ceo@clay.com`). Includes OR together; excludes always apply. Narrows the feed to email events."
          schema:
            type: string
            minLength: 1
            maxLength: 2048
        - name: eventType
          in: query
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: automationId
          in: query
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: sendId
          in: query
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: messageClass
          in: query
          required: false
          description: Admission snapshot on the send behind the event (`marketing` | `transactional`). Same event object for both classes; absent stamps match as marketing. Narrows the feed to email events.
          schema:
            type: string
            enum:
              - marketing
              - transactional
        - name: transactionId
          in: query
          required: false
          description: "Transactional-object scope (`txn_…`): events from EVERY fire of one reusable transactional email object. Prefer this over `sendId` for object-level reporting; rows carry `transactionId` back. Narrows the feed to email events."
          schema:
            type: string
            minLength: 1
            maxLength: 128
        - name: source
          in: query
          required: false
          description: "Send-object facet: CSV of send sources (valid values: audience, api, automation_manual, automation_integration, automation_custom). Narrows the feed to email events."
          schema:
            type: string
            minLength: 1
            maxLength: 256
        - name: audienceId
          in: query
          required: false
          description: "Send-object facet: CSV of audience ids (max 20) — events from the audiences' sends. Narrows the feed to email events."
          schema:
            type: string
            minLength: 1
            maxLength: 2048
        - name: emailId
          in: query
          required: false
          description: "Send-object facet: one email design id. Narrows the feed to email events."
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: domain
          in: query
          required: false
          description: "Send-object facet: a sending domain (`fromEmail` match). Narrows the feed to email events."
          schema:
            type: string
            minLength: 1
            maxLength: 255
        - name: triggerEventId
          in: query
          required: false
          description: "Send-object facet: CSV of integration trigger-event ids (max 10), resolved to their wired automations. Narrows the feed to email events."
          schema:
            type: string
            minLength: 1
            maxLength: 2048
        - name: includeMachineClicks
          in: query
          required: false
          description: "Machine/bot-classified `clicked` rows are excluded by default. Pass `true` to include the raw rows (they carry `machineGenerated: true` + a `clickBotReason`; audit/debug only)."
          schema:
            type: boolean
        - name: includeMachineOpens
          in: query
          required: false
          description: Machine/bot-classified `opened` rows (security-scanner pixel detonation, Apple-proxy prefetch) and still-classifying opens are excluded by default. Pass `true` to include the raw rows (they carry `machineGenerated` + an `openBotReason` and `openFetchSource`; audit/debug only).
          schema:
            type: boolean
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
        - name: cursor
          in: query
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 8192
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: A page of unified analytics events.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EventsAnalyticsResponse"
              example:
                data:
                  - id: evt_abc
                    occurredAt: 2026-04-08T12:34:56.789Z
                    domain: email
                    eventType: opened
                    recipientEmail: jane@example.com
                    sendId: snd_8fK2mQ4p
                    emailId: eml_launch
                    emailName: Spring Launch
                pagination:
                  limit: 50
                  cursor: null
                  hasMore: false
                range:
                  from: 2026-04-01T12:34:56.789Z
                  to: 2026-04-08T12:34:56.789Z
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: eventType
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations:
    post:
      operationId: createAutomation
      tags:
        - Automations
      summary: Create an automation
      description: |-
        Deterministic create — the body carries the full graph (`{ name, triggerEventId?, nodes, connections }`). Returns `201` with the bare `AutomationRow`.

        **Trigger binding (exactly one):** for an EVENT automation pass `triggerEventId` (then publish with `PATCH … { "published": true }`). For a MANUAL-AUDIENCE automation OMIT `triggerEventId` and give the trigger node `config: { "mode": "manualAudience", "audienceId": "aud_…" }` — it is launched on demand with `POST /v1/automations/{automationId}/run` rather than published.

        **Typed conditions:** every filter and condition-mode split uses a non-empty `conditions` array. Each condition requires `field`, `type` (`string`, `number`, `date`, or `bool`), and a canonical snake_case `operator`. Unary operators omit `value`; comparisons require a type-correct scalar, non-empty array, or exact two-value `between` tuple as documented by `AutomationNode`.

        Chain `POST /v1/emails { prompt }` first to mint the design each `sendEmail` node references — every `sendEmail` node MUST carry `emailId`, `emailVersionId`, `subject` (`previewText` is optional: the email design's JSX `<Preview>` is the preview source of truth). `domainId` is optional on create/save; publishing (`PATCH … { published: true }`) or running (`POST …/run`) requires a verified `domainId` from `GET /v1/domains`. `messageClass` is optional and behaves as `"marketing"` at send time when unset.

        **Dry-run** — add `dryRun: true` (alias `dry_run`) to validate without persisting; returns `200` with an `AutomationDryRunReport`: `{ valid, blockers[], warnings[], blockingIssues[], nodeCounts }`. `blockers[]` (severity `error`) fail publish; `warnings[]` are advisory. `blockingIssues[]` lists per-node references the bound trigger or contact catalog cannot provide. `valid` is false when any blocker or any blocking issue is present.
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AutomationsPostRequest"
            examples:
              deterministic:
                summary: Create a trigger → sendEmail flow
                value:
                  name: Welcome flow
                  description: Welcome new signups
                  triggerEventId: tri_signup
                  nodes:
                    - &a9
                      id: trg
                      label: On signup
                      type: trigger
                      config:
                        actionType: trigger
                    - &a10
                      id: send_welcome
                      label: Welcome
                      type: sendEmail
                      config:
                        actionType: sendEmail
                        emailId: eml_welcome
                        emailVersionId: emv_welcome_v1
                        domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                        subject: Welcome to Brew, {{firstName | there}}!
                        previewText: Thanks for signing up — get started in 2 minutes.
                        fromName: Brew
                        replyTo: support@example.com
                  connections:
                    - from: trg
                      to: send_welcome
              dryRun:
                summary: Validate without persisting
                value:
                  name: preview
                  triggerEventId: tri_signup
                  nodes:
                    - *a9
                  connections: []
                  dryRun: true
      responses:
        "200":
          description: "Dry-run result (returned only for `dryRun: true`; no writes). `valid` is false when any `blockers[]` entry or any `blockingIssues[]` entry is present. Create and update both return `blockingIssues[]` (possibly empty)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationDryRunReport"
              example:
                valid: false
                blockers:
                  - severity: error
                    message: Add at least one Send Email action
                warnings: []
                blockingIssues: []
                nodeCounts:
                  sendEmail: 0
                  wait: 0
                  filter: 0
                  split: 0
        "201":
          description: Created. The bare automation row (draft, full graph).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationRow"
              example:
                automationId: auto_abc
                automationVersionId: av_v1
                triggerEventId: tri_signup
                name: Welcome flow
                version: latest
                published: false
                isLive: false
                nodes: &a11
                  - *a9
                  - *a10
                connections: &a12
                  - from: trg
                    to: send_welcome
                emailIds: &a13
                  - eml_welcome
                createdAt: 2026-04-08T12:00:00.000Z
                updatedAt: 2026-04-08T12:00:00.000Z
        "400":
          description: Strict-body violation OR the graph references designs / domains that do not exist or are not ready. `AUTOMATION_GRAPH_INVALID` includes `error.details.issues` with one entry per offending node / connection.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              examples:
                schemaInvalid:
                  summary: Required field missing
                  value:
                    error:
                      code: INVALID_REQUEST
                      type: invalid_request
                      message: Request body validation failed.
                      suggestion: Send `{ name, triggerEventId, nodes, connections }` with each sendEmail node carrying `emailId`, `emailVersionId`, `subject`. `previewText` and `domainId` are optional on create; `domainId` is required before publish or live run.
                      docs: https://docs.brew.new/api-reference/api/errors
                graphInvalid:
                  summary: Graph references unknown email / domain
                  value:
                    error:
                      code: AUTOMATION_GRAPH_INVALID
                      type: invalid_request
                      message: "\"Welcome\" references emailVersionId 'emv_missing' which does not exist in this brand. (and 1 more graph issue)"
                      param: nodes[0].config.emailVersionId
                      suggestion: Fix every issue reported in `details.issues` then resubmit. Each entry includes the offending `nodeId` (or connection index) and a `kind` discriminator your SDK can branch on.
                      docs: https://docs.brew.new/api-reference/api/errors
                      details:
                        issues:
                          - kind: email_not_found
                            nodeId: send_welcome
                            nodeLabel: Welcome
                            message: "\"Welcome\" references emailVersionId 'emv_missing' which does not exist in this brand. Generate the email via POST /v1/emails and reuse the returned emailId + emailVersionId."
                          - kind: domain_not_ready
                            nodeId: send_welcome
                            nodeLabel: Welcome
                            message: "\"Welcome\" references domain 'kx7…' which is not verified for sending. Finish domain verification or pick a different domainId."
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: The referenced `triggerEventId` does not exist.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: TRIGGER_EVENT_NOT_FOUND
                  type: not_found
                  message: Trigger event 'tri_unknown' was not found in this brand.
                  suggestion: Pass a triggerEventId returned by POST /v1/automations/triggers.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: triggerEventId
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    get:
      operationId: listAutomations
      tags:
        - Automations
      summary: Get automations
      description: "Unified automation read. Omit `automationId` to LIST the brand’s automations under `{ data, pagination }` — list rows are LEAN (graph omitted). Pass `?automationId=` to fetch ONE — returns `{ data: [row] }` (no `pagination`), `404 AUTOMATION_NOT_FOUND` on an unknown / cross-brand id, also LEAN by default. Add detail-only `?include=graph` (the full `nodes` + `connections`) and/or `?include=versions` (lean `{ version, automationVersionId }` history) — both rejected without `automationId`."
      parameters:
        - name: automationId
          in: query
          required: false
          description: "Fetch a single automation by id (detail mode → `{ data: [row] }`). Omit to list."
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: include
          in: query
          required: false
          description: "Detail-only expansions (comma-separated): `graph` inlines `nodes`/`connections`; `versions` inlines the lean version history. Rejected without `automationId`."
          schema:
            type: string
            example: graph,versions
        - *a7
        - *a8
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "A page of lean automation rows (list mode), or `{ data: [row] }` (detail mode)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationsListResponse"
              example:
                data:
                  - automationId: auto_abc
                    automationVersionId: av_v1
                    triggerEventId: tri_signup
                    name: Welcome flow
                    version: latest
                    published: true
                    emailIds:
                      - eml_welcome
                    updatedAt: 2026-04-08T12:00:00.000Z
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: limit
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: Automation not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: &a14
                error:
                  code: AUTOMATION_NOT_FOUND
                  type: not_found
                  message: Automation 'auto_xxx' was not found.
                  suggestion: List automations with GET /v1/automations.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: automationId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations/{automationId}:
    patch:
      operationId: updateAutomation
      tags:
        - Automations
      summary: Update or publish an automation
      description: |-
        One endpoint, two mutually-exclusive modes:

        - **Update** — supply one or more of `name`, `description`, `nodes`, `connections`, `triggerEventId`. Graph updates persist a new `automationVersionId` on the same `automationId`. Add `dryRun: true` (alias `dry_run`) to validate a graph update without persisting.
        - **Lifecycle** — supply `published: true` to promote the stored latest version live (validates the graph first → `409 PUBLISH_VALIDATION_FAILED` on blockers; optionally pin `automationVersionId` to publish a specific version), or `published: false` to unpublish.

        Graph updates use the same strict typed filter/split condition contract as create: explicit `type`, canonical snake_case `operator`, no `value` for unary operators, and type-correct values everywhere else.

        **Dry-run** — with `dryRun: true` the `200` body is an `AutomationDryRunReport` instead of the row: `{ valid, blockers[], warnings[], blockingIssues[], nodeCounts }`. `blockingIssues[]` lists per-node references the effective trigger or contact catalog cannot provide. `fatal: true` (filter/split conditions and triple-brace `{{{ }}}` body tokens) fails publish; `fatal: false` (subject/previewText/fromName/replyTo and double-brace body tags) renders empty at send time. Dry-run `valid` is false when any blocker or any blocking issue is present; publish itself still hard-blocks only fatal issues so a live automation can be republished after a soft orphan.

        The two modes cannot be combined: publishing promotes the stored graph, so update first, then PATCH `{ "published": true }`. Returns the bare automation row (or the dry-run report when `dryRun: true`).

        **Updating a LIVE automation saves a draft — it does not go live.** The previously published version keeps serving until you republish. The response row carries the truthful state: `published` describes the returned row, `isLive`/`liveVersion`/`liveAutomationVersionId` describe the automation, and a `warnings` entry with code `DRAFT_SAVED_NOT_LIVE` flags that your saved edit is not yet serving.
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Automation id returned by `POST /v1/automations` and listed by `GET /v1/automations`.
            example: auto_abc
          required: true
          description: Automation id returned by `POST /v1/automations` and listed by `GET /v1/automations`.
          name: automationId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AutomationsUpdateRequest"
            examples:
              rename:
                summary: Rename
                value:
                  name: Welcome flow v2
              graph:
                summary: Replace the graph
                value:
                  nodes:
                    - *a9
                    - *a10
                  connections:
                    - from: trg
                      to: send_welcome
              dryRun:
                summary: Validate a graph update without persisting
                value:
                  nodes:
                    - *a9
                    - *a10
                  connections:
                    - from: trg
                      to: send_welcome
                  dryRun: true
              publish:
                summary: Publish (promote live)
                value:
                  published: true
              publishVersion:
                summary: Publish a pinned version
                value:
                  published: true
                  automationVersionId: av_v2
              unpublish:
                summary: Unpublish
                value:
                  published: false
      responses:
        "200":
          description: "Updated / published / unpublished — the bare automation row. For `dryRun: true` update requests, an `AutomationDryRunReport` instead (no writes)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/AutomationRow"
                  - $ref: "#/components/schemas/AutomationDryRunReport"
              examples:
                updated:
                  summary: Updated / published — the automation row
                  value:
                    automationId: auto_abc
                    automationVersionId: av_v1
                    triggerEventId: tri_signup
                    name: Welcome flow
                    version: latest
                    published: false
                    isLive: true
                    liveVersion: 3
                    liveAutomationVersionId: av_v3
                    nodes: *a11
                    connections: *a12
                    emailIds: *a13
                    createdAt: 2026-04-08T12:00:00.000Z
                    updatedAt: 2026-04-08T12:00:00.000Z
                dryRun:
                  summary: "Dry-run validation report (`dryRun: true`)"
                  value:
                    valid: false
                    blockers: []
                    warnings: []
                    blockingIssues:
                      - nodeId: filter_a1b2
                        nodeLabel: Paid plan
                        surface: filterCondition
                        variable: plan
                        reason: Condition on "plan", which the trigger doesn't provide
                        fatal: true
                        hasFallback: false
                    nodeCounts:
                      sendEmail: 1
                      wait: 0
                      filter: 1
                      split: 0
        "400":
          description: Strict-body violation, no actionable field supplied, `published` combined with update fields, or `AUTOMATION_GRAPH_INVALID` (see `details.issues`).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Provide `published` to publish/unpublish, or at least one of `name`, `description`, `nodes`, `connections`, or `triggerEventId` to update.
                  suggestion: Send a lifecycle (`published`) or at least one editable field.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: published
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: Automation not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a14
        "409":
          description: "`PUBLISH_VALIDATION_FAILED` — `published: true` but the graph has blockers (see `details.blockers`). `AUTOMATION_VERSION_CONFLICT` — concurrent or stale draft commit; re-read the latest version, reapply the intended changes, and retry."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              examples:
                publishValidation:
                  summary: Publish blocked by graph validation
                  value:
                    error:
                      code: PUBLISH_VALIDATION_FAILED
                      type: conflict
                      message: Add at least one Send Email action
                      suggestion: Fix every blocker reported in `details.blockers` then publish again.
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: published
                versionConflict:
                  summary: Stale draft commit
                  value:
                    error:
                      code: AUTOMATION_VERSION_CONFLICT
                      type: conflict
                      message: This automation changed while the draft was being saved.
                      suggestion: Read the latest automation version, reapply the intended changes, and retry the update.
                      docs: https://docs.brew.new/api-reference/api/errors
        "422":
          description: "`AUTOMATION_NOT_PUBLISHED` — `published: false` but the automation was never published (nothing to unpublish)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: AUTOMATION_NOT_PUBLISHED
                  type: invalid_request
                  message: Automation 'auto_abc' is not currently published — nothing to unpublish.
                  suggestion: Verify the automation is published via GET /v1/automations?automationId=.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: published
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    delete:
      operationId: deleteAutomation
      tags:
        - Automations
      summary: Delete an automation
      description: "Cascade-deletes the automation: every version row, runs, and logs. Referenced email DESIGNS are shared resources and always survive. Idempotent — an unknown id resolves with `deleted: false`."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Automation id returned by `POST /v1/automations` and listed by `GET /v1/automations`.
            example: auto_abc
          required: true
          description: Automation id returned by `POST /v1/automations` and listed by `GET /v1/automations`.
          name: automationId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Deleted (or already gone).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationsDeleteResponse"
              example:
                automationId: auto_abc
                deleted: true
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations/{automationId}/test:
    post:
      operationId: testAutomation
      tags:
        - Automations
      summary: Test an automation
      description: Runs the saved automation END-TO-END through the real workflow in TEST mode — works on drafts and for both event and manual-audience automations; every node executes (filters/splits evaluate against `payload`, wait nodes fast-forward). Pass `testRecipient` to DELIVER each send-email node’s email for real to that address (real subject/preview/sender name via the Brew test domain; customer addresses are never hit) — omit it for a silent dry-run with no mail. Test runs never count against analytics rollups or send quotas. Returns `202` with the started run id; follow per-node status via `GET /v1/automations/runs?automationRunId=&include=logs`.
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Automation id returned by `POST /v1/automations` and listed by `GET /v1/automations`.
            example: auto_abc
          required: true
          description: Automation id returned by `POST /v1/automations` and listed by `GET /v1/automations`.
          name: automationId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AutomationTestRequest"
            example:
              payload:
                email: qa@example.com
                plan: pro
              testRecipient: qa@example.com
      responses:
        "202":
          description: Test run started.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationRunStartedResponse"
              example:
                automationRunIds:
                  - run_01HZ
                status: test_started
                receivedAt: 2026-04-08T12:34:56.789Z
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: payload
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: Automation not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a14
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations/{automationId}/run:
    post:
      operationId: runAutomation
      tags:
        - Automations
      summary: Run a manual-audience automation
      description: "Launches a MANUAL-AUDIENCE automation against the audience bound to its trigger node. `dryRun: true` (alias `dry_run`) previews without sending; `scheduledAt` launches later. Percentage-based `gradualSend` delivers each send step in custom hour or calendar-day batches and supports manual pause/resume/cancel. `400` when the resolved plan exceeds 50,000 recipients, 30 batches, or 30 elapsed days. Returns `202` with the `audienceRunId`."
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Automation id returned by `POST /v1/automations` and listed by `GET /v1/automations`.
            example: auto_abc
          required: true
          description: Automation id returned by `POST /v1/automations` and listed by `GET /v1/automations`.
          name: automationId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AutomationRunRequest"
            example:
              scheduledAt: 2026-07-01T15:00:00.000Z
      responses:
        "200":
          description: Dry-run preview (no run started).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationRunDryRunResponse"
              example:
                dry_run: true
                automationId: auto_abc
                audienceId: aud_123
                audienceName: Active trial users
                recipientCount: 12400
                sendNodeCount: 2
        "202":
          description: 'Run launched (or scheduled). When org-level send approval is enabled the body additionally carries `approvalState: "pending"`.'
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AudienceAutomationRunStartedResponse"
              example:
                audienceRunId: arun_01HZ
                automationId: auto_abc
                status: queued
                totalRecipients: 12400
                receivedAt: 2026-04-08T12:34:56.789Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: Automation not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a14
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations/audience-runs:
    get:
      operationId: listAudienceRuns
      tags:
        - Automations
      summary: List manual-audience runs
      description: Lists manual-audience automation runs (each "Run" of a manual-audience automation), newest first — status, recipient totals, and the per-node funnel. Pass `?audienceRunId=` to fetch one, or `?automationId=` to filter to a single automation.
      parameters:
        - name: audienceRunId
          in: query
          required: false
          description: Fetch a single audience run by id.
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: automationId
          in: query
          required: false
          description: Filter runs to a single automation.
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: limit
          in: query
          required: false
          description: Max rows to return (1–200, default 50).
          schema:
            type: integer
            minimum: 1
            maximum: 200
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "Audience runs (list mode), or `{ data: [row] }` (detail)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AudienceRunsListResponse"
              example:
                data:
                  - audienceRunId: arun_01HZ
                    automationId: auto_abc
                    audienceId: aud_123
                    audienceName: Active trial users
                    status: sent
                    totalRecipients: 12400
                    sentCount: 12180
                    failedCount: 0
                    skippedCount: 220
                    createdAt: 2026-04-08T12:34:56.789Z
                    updatedAt: 2026-04-08T12:41:10.000Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations/audience-runs/{audienceRunId}/control:
    post:
      operationId: controlAudienceRun
      tags:
        - Automations
      summary: Pause, resume, or cancel a manual-audience run
      description: Controls an in-flight manual-audience run. `pause` holds delivery at the next step boundary (resumable); `resume` continues a paused run; `cancel` stops it for good — emails already sent are NOT recalled and a canceled run can't be resumed. `409` if the run is not in a state that allows the action (e.g. resuming a run that isn't paused); `404` for an unknown `audienceRunId`.
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: The audience run id (from `POST /v1/automations/{automationId}/run` or `GET /v1/automations/audience-runs`).
            example: arun_01HZ
          required: true
          description: The audience run id (from `POST /v1/automations/{automationId}/run` or `GET /v1/automations/audience-runs`).
          name: audienceRunId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AudienceRunControlRequest"
            example:
              action: pause
      responses:
        "200":
          description: The run's new status after the control action.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AudienceRunControlResponse"
              example:
                audienceRunId: arun_01HZ
                status: paused
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: Audience run not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: NOT_FOUND
                  type: not_found
                  message: Audience run 'arun_xxx' was not found.
                  suggestion: List runs with GET /v1/automations/audience-runs.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: audienceRunId
        "409":
          description: The run is not in a state that allows the action (e.g. pausing a run that already finished, or resuming a run that is not paused).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RUN_NOT_PAUSABLE
                  type: conflict
                  message: This run is already sent and can’t be paused.
                  suggestion: Only a running run can be paused.
                  docs: https://docs.brew.new/api-reference/api/errors
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations/runs:
    get:
      operationId: listAutomationRuns
      tags:
        - Automations
      summary: Get automation runs
      description: "Unified automation-run read. Omit `automationRunId` to LIST recent runs (newest first) under `{ data, pagination }`. Filters: `automationId`, `triggerEventId`, `triggerInstanceId`, `recipientEmail`, `status` (pending | running | completed | failed | canceled), `mode` (live | test), and the `from`/`to` ISO-8601 window. Pass `?automationRunId=` to fetch ONE run — returns `{ data: [row] }` (no `pagination`), `404 AUTOMATION_RUN_NOT_FOUND` on an unknown / cross-brand id. List + detail rows are lean by default; add `?include=logs` (detail only) for the per-node execution `logs[]`."
      parameters:
        - name: automationRunId
          in: query
          required: false
          description: "Fetch a single run by id (detail mode → `{ data: [row] }`). Omit to list."
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: include
          in: query
          required: false
          description: "Detail-only expansion: `logs` inlines the per-node execution logs. Rejected without `automationRunId`."
          schema:
            type: string
            enum:
              - logs
        - name: automationId
          in: query
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: triggerEventId
          in: query
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 256
        - name: triggerInstanceId
          in: query
          required: false
          schema:
            type: string
            minLength: 4
            maxLength: 64
        - name: recipientEmail
          in: query
          required: false
          schema:
            type: string
            format: email
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - pending
              - running
              - completed
              - failed
              - canceled
        - name: mode
          in: query
          required: false
          schema:
            type: string
            enum:
              - live
              - test
        - name: from
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: false
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
        - name: cursor
          in: query
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 256
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: A page of runs.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationRunsListResponse"
              example:
                data:
                  - automationRunId: run_01HZ
                    automationId: auto_abc
                    automationVersionId: av_v2
                    triggerInstanceId: tin_8f2k
                    mode: live
                    status: completed
                    recipientEmail: jane@example.com
                    startedAt: 2026-04-08T12:34:56.789Z
                    completedAt: 2026-04-08T12:35:10.120Z
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: status
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: Automation run not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: AUTOMATION_RUN_NOT_FOUND
                  type: not_found
                  message: Automation run 'run_xxx' was not found.
                  suggestion: List runs with GET /v1/automations/runs.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: automationRunId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations/triggers:
    post:
      operationId: createTrigger
      tags:
        - Automations
      summary: Create a trigger
      description: |-
        Creates a custom trigger event definition — the contract automations subscribe to. Body carries `{ title, description?, payloadSchema }`; the server mints `triggerEventId` and hardcodes `provider: "brew_api"`. Integration triggers (clerk, stripe, shopify, …) are provisioned by the corresponding integration only.

        `payloadSchema.fields` MUST declare `{ key: "email", type: "string", required: true }` so downstream automations can resolve a recipient. Returns `201` with the bare trigger row.
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TriggersPostRequest"
            example:
              title: User Signed Up
              description: Fires when a user completes signup.
              payloadSchema:
                type: object
                fields:
                  - key: email
                    type: string
                    required: true
                  - key: firstName
                    type: string
                    required: false
      responses:
        "201":
          description: Created. The bare trigger row.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriggerRow"
              example: &a15
                triggerEventId: tri_signup
                title: User Signed Up
                description: Fires when a user completes signup.
                provider: brew_api
                payloadSchema:
                  type: object
                  fields:
                    - key: email
                      type: string
                      required: true
                    - key: firstName
                      type: string
                      required: false
                createdAt: 2026-04-08T12:00:00.000Z
                updatedAt: 2026-04-08T12:00:00.000Z
        "400":
          description: Strict-body violation — unknown keys (including `provider` / `providerEventKey`) or a payload schema without the required `email` field.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: PAYLOAD_SCHEMA_EMAIL_REQUIRED
                  type: invalid_request
                  message: 'payloadSchema.fields must declare { key: "email", type: "string", required: true }.'
                  suggestion: Add the required email field to payloadSchema.fields.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: payloadSchema
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    get:
      operationId: listTriggers
      tags:
        - Automations
      summary: Get triggers
      description: 'Unified trigger read. Omit `triggerEventId` to LIST every trigger the brand has under `{ data, pagination }` — `provider: "brew_api"` for API-created customs and `provider: "clerk" | "stripe" | …` for integration-provisioned triggers. Pass `?triggerEventId=` to fetch ONE — returns `{ data: [row] }` (no `pagination`), `404 TRIGGER_NOT_FOUND` on an unknown / cross-brand id.'
      parameters:
        - name: triggerEventId
          in: query
          required: false
          description: "Fetch a single trigger by id (detail mode → `{ data: [row] }`). Omit to list."
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: include
          in: query
          required: false
          description: "Detail mode only: pass `skill` to add a `skill` field to the row — a SKILL.md-shaped wiring brief for the fire endpoint. Ignored in list mode."
          schema:
            type: string
            enum:
              - skill
        - *a7
        - *a8
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "A page of trigger rows (list mode), or `{ data: [row] }` (detail mode)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriggersListResponse"
              example:
                data:
                  - *a15
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: limit
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: Trigger not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: &a16
                error:
                  code: TRIGGER_EVENT_NOT_FOUND
                  type: not_found
                  message: Trigger event 'tri_xxx' was not found.
                  suggestion: List triggers with GET /v1/automations/triggers.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: triggerEventId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations/triggers/{triggerEventId}:
    patch:
      operationId: updateTrigger
      tags:
        - Automations
      summary: Update a trigger
      description: Updates one or more editable fields (`title`, `description`, `payloadSchema`). Whether a trigger fires is governed solely by `automation.published` on each wired automation — there is no per-trigger off-switch. Integration-provisioned triggers are immutable here (`422 TRIGGER_IMMUTABLE`). Returns the bare updated row.
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 256
            description: Trigger id returned by `POST /v1/automations/triggers`. Custom triggers use `tri_…` ids; integration triggers use composite ids (e.g. `clerk:org_…:brand_…:user.created`, URL-encode the colons).
            example: tri_signup
          required: true
          description: Trigger id returned by `POST /v1/automations/triggers`. Custom triggers use `tri_…` ids; integration triggers use composite ids (e.g. `clerk:org_…:brand_…:user.created`, URL-encode the colons).
          name: triggerEventId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TriggersPatchRequest"
            example:
              title: User Signed Up (v2)
      responses:
        "200":
          description: Updated.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriggerRow"
              example: *a15
        "400":
          description: Strict-body violation or no editable field supplied (a bare id with no updates is rejected).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: title
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: Trigger not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a16
        "422":
          description: Integration-provisioned trigger — manage it from the integration instead.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: TRIGGER_IMMUTABLE
                  type: invalid_request
                  message: Integration triggers are managed by their provider and cannot be edited via the API.
                  suggestion: Edit the event configuration in the integration that provisioned this trigger.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: triggerEventId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    delete:
      operationId: deleteTrigger
      tags:
        - Automations
      summary: Delete a trigger
      description: "Deletes a custom trigger. Refused with `409 TRIGGER_HAS_DEPENDENT_AUTOMATIONS` while automations still reference it (`details.referencingAutomations` lists each blocker). Idempotent — an already-gone trigger resolves with `deleted: false`."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 256
            description: Trigger id returned by `POST /v1/automations/triggers`. Custom triggers use `tri_…` ids; integration triggers use composite ids (e.g. `clerk:org_…:brand_…:user.created`, URL-encode the colons).
            example: tri_signup
          required: true
          description: Trigger id returned by `POST /v1/automations/triggers`. Custom triggers use `tri_…` ids; integration triggers use composite ids (e.g. `clerk:org_…:brand_…:user.created`, URL-encode the colons).
          name: triggerEventId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Deleted (or already gone).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriggersDeleteResponse"
              example:
                triggerEventId: tri_signup
                deleted: true
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "409":
          description: Automations still reference this trigger.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              examples:
                dependentAutomations:
                  summary: Blocked by referencing automations
                  value:
                    error:
                      code: TRIGGER_HAS_DEPENDENT_AUTOMATIONS
                      type: conflict
                      message: Trigger 'tri_signup' is referenced by 1 automation and cannot be deleted.
                      suggestion: Delete or detach the automations listed in `details.referencingAutomations` first.
                      docs: https://docs.brew.new/api-reference/api/errors
                      param: triggerEventId
                      details:
                        referencingAutomations:
                          - automationId: auto_abc
                            name: Welcome flow
                            published: true
        "422":
          description: Integration-provisioned trigger — cannot be deleted.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: TRIGGER_IMMUTABLE
                  type: invalid_request
                  message: Integration triggers are managed by their provider and cannot be deleted via the API.
                  suggestion: Disconnect the event in the integration that provisioned this trigger.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: triggerEventId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/automations/triggers/{triggerEventId}/fire:
    get:
      operationId: checkTriggerReady
      tags:
        - Automations
      summary: Pre-flight a trigger (ready check)
      description: |-
        Verifies a fire would be accepted WITHOUT firing: authenticates the key, resolves the trigger in your organization/brand scope, and checks permissions — the same gates a real `POST` hits. `status: "ready"` returns the contract a caller needs to wire an external service: `details.payloadSchema`, `details.endpoint`, and the matched published consumers (`publishedAutomations`, `publishedTransactionalEmails`, `counts`).

        Use it while integrating, before anything is published: a ready trigger with `counts.automations: 0` accepts fires but starts no runs until an attached automation is published.

        **Response-shape note** — responds with the same legacy fire envelope as the `POST` (`{ success, status, code, message, receivedAt, details }`).
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 256
            description: Trigger id returned by `POST /v1/automations/triggers`. Custom triggers use `tri_…` ids; integration triggers use composite ids (e.g. `clerk:org_…:brand_…:user.created`, URL-encode the colons).
            example: tri_signup
          required: true
          description: Trigger id returned by `POST /v1/automations/triggers`. Custom triggers use `tri_…` ids; integration triggers use composite ids (e.g. `clerk:org_…:brand_…:user.created`, URL-encode the colons).
          name: triggerEventId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "Ready: the key, scope, and permissions all pass; `details` carries the payload contract and matched consumers."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriggerFireResponse"
              example:
                success: true
                status: ready
                code: TRIGGER_EVENT_READY
                message: Trigger event definition loaded successfully.
                triggerEventId: tri_signup
                receivedAt: 2026-04-08T12:34:56.789Z
                details:
                  title: User Signed Up
                  provider: brew_api
                  payloadSchema:
                    type: object
                    fields:
                      - key: email
                        type: string
                        required: true
                      - key: firstName
                        type: string
                        required: false
                  endpoint:
                    method: POST
                    path: /v1/automations/triggers/tri_signup/fire
                  publishedAutomations:
                    - automationId: auto_abc
                      title: Welcome flow
                  publishedTransactionalEmails: []
                  counts:
                    transactionalEmails: 0
                    automations: 1
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    post:
      operationId: fireTrigger
      tags:
        - Automations
      summary: Fire a trigger
      description: |-
        Fires the trigger: validates `payload` against the trigger’s `payloadSchema`, upserts the contact derived from the payload, and starts one run per published automation attached to the trigger. Read `details.automationRunIds[]` and follow each via `GET /v1/automations/runs?automationRunId=`.

        **Idempotency** — send a stable `Idempotency-Key` header on every retry (the body field `idempotencyKey` is a legacy alternative). Replays return the original run ids with `status: "idempotent_replay"` instead of starting duplicates.

        **Response-shape note** — this endpoint responds with the legacy fire envelope `{ success, status, code, message, receivedAt, details }` (shared with internal webhook infrastructure) rather than a bare resource. It is the ONE exception to the v1 response conventions; treat `status` + `code` as the discriminators.
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 256
            description: Trigger id returned by `POST /v1/automations/triggers`. Custom triggers use `tri_…` ids; integration triggers use composite ids (e.g. `clerk:org_…:brand_…:user.created`, URL-encode the colons).
            example: tri_signup
          required: true
          description: Trigger id returned by `POST /v1/automations/triggers`. Custom triggers use `tri_…` ids; integration triggers use composite ids (e.g. `clerk:org_…:brand_…:user.created`, URL-encode the colons).
          name: triggerEventId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TriggerFireRequest"
            example:
              payload:
                email: jane@example.com
                firstName: Jane
      responses:
        "200":
          description: 'Fired (`status: "triggered"`) or idempotent replay (`status: "idempotent_replay"`). `details.automationRunIds[]` carries one run id per matched published automation.'
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriggerFireResponse"
              example:
                success: true
                status: triggered
                code: TRIGGERED
                message: Trigger event accepted and matched published attachments.
                triggerEventId: tri_signup
                receivedAt: 2026-04-08T12:34:56.789Z
                details:
                  resolvedPayload:
                    email: jane@example.com
                    firstName: Jane
                  triggerInstanceId: tin_8f2k
                  publishedAutomations:
                    - automationId: auto_abc
                      title: Welcome flow
                  automationRunIds:
                    - run_01HZ
                  counts:
                    transactionalEmails: 0
                    automations: 1
        "400":
          description: 'Invalid JSON, or the payload does not satisfy the trigger’s `payloadSchema` (`status: "payload_mismatch"`). Errors use the same fire envelope with `success: false`.'
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriggerFireResponse"
              example:
                success: false
                status: payload_mismatch
                code: PAYLOAD_MISMATCH
                message: Required field 'email' is missing from the payload.
                triggerEventId: tri_signup
                receivedAt: 2026-04-08T12:34:56.789Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: The trigger does not exist in the API-key brand.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriggerFireResponse"
              example:
                success: false
                status: trigger_event_not_found
                code: TRIGGER_EVENT_NOT_FOUND
                message: Trigger event 'tri_xxx' was not found.
                receivedAt: 2026-04-08T12:34:56.789Z
        "422":
          description: No published automation is attached to the trigger.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriggerFireResponse"
              example:
                success: false
                status: failed
                code: NO_PUBLISHED_AUTOMATION
                message: Trigger event 'tri_signup' has no published automation attached.
                triggerEventId: tri_signup
                receivedAt: 2026-04-08T12:34:56.789Z
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/analytics/trigger-instances:
    get:
      operationId: listEvents
      tags:
        - Analytics
      summary: Get fired trigger events
      description: 'Unified fired-trigger-event read. Omit `triggerInstanceId` to LIST fired instances (newest first) under `{ data, pagination }` — the audit log of every inbound fire, whether from the API (`source: "api"`) or an integration webhook (`source: "integration"`). Each row links the fire to the automations it matched and the runs it started (`automationRunIds[]` → `GET /v1/automations/runs?automationRunId=`). Filter with `?triggerEventId=`. Pass `?triggerInstanceId=` to fetch ONE — returns `{ data: [row] }` (no `pagination`), `404 EVENT_NOT_FOUND` on an unknown / cross-brand id.'
      parameters:
        - name: triggerInstanceId
          in: query
          required: false
          description: "Fetch a single fired event by id (detail mode → `{ data: [row] }`). Omit to list."
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: triggerEventId
          in: query
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 256
        - *a7
        - *a8
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "A page of fired trigger-event instances (list mode), or `{ data: [row] }` (detail mode)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EventsListResponse"
              example:
                data:
                  - triggerInstanceId: tin_8f2k
                    source: api
                    provider: brew_api
                    triggerEventId: tri_signup
                    state: processed
                    matchedAutomationIds:
                      - auto_abc
                    automationRunIds:
                      - run_01HZ
                    attempts: 1
                    receivedAt: 2026-04-08T12:34:56.789Z
                    processedAt: 2026-04-08T12:34:57.100Z
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: triggerEventId
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `automations` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: automations
        "404":
          description: Fired trigger event not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: EVENT_NOT_FOUND
                  type: not_found
                  message: No fired event was found with id 'tin_xxx'.
                  suggestion: List fired events with GET /v1/analytics/trigger-instances.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: triggerInstanceId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/contacts:
    post:
      operationId: upsertContacts
      tags:
        - Contacts
      summary: Create or update contacts
      description: |-
        Upserts a single contact OR a batch (`{ contacts: [...] }`, up to 1000 rows). Unknown custom fields auto-create field definitions on the brand.

        Single: `201` with `{ contact, created, fieldsCreated, warnings }`. Batch: `200` with `{ summary, fieldsCreated, errors, warnings }` — or `207` when some rows failed (per-row errors in `errors[]`).
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactsPostRequest"
            examples:
              single:
                summary: Upsert a single contact
                value:
                  email: jane@example.com
                  firstName: Jane
                  customFields:
                    plan: enterprise
              batch:
                summary: Upsert a batch
                value:
                  contacts:
                    - email: jane@example.com
                      firstName: Jane
                    - email: john@example.com
                      firstName: John
      responses:
        "200":
          description: Batch upsert applied (every row succeeded).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactsPostBatchResponse"
              example:
                summary:
                  inserted: 2
                  updated: 0
                  failed: 0
                fieldsCreated: []
                errors: []
                warnings: []
        "201":
          description: Single upsert applied.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactsPostSingleResponse"
              example:
                contact: &a18
                  email: jane@example.com
                  firstName: Jane
                  lastName: Doe
                  subscribed: true
                  validationStatus: valid
                  verificationStatus: valid
                  suppressed: false
                  suppressedReason: null
                  createdAt: 2026-04-08T12:00:00.000Z
                  updatedAt: 2026-04-08T12:05:00.000Z
                  importId: null
                  customFields: &a17
                    plan: enterprise
                    revenue: 4200
                created: true
                fieldsCreated:
                  - plan
                warnings: []
        "207":
          description: Batch partially applied — inspect `errors[]` for each failed row.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactsPostBatchResponse"
              example:
                summary:
                  inserted: 1
                  updated: 0
                  failed: 1
                fieldsCreated: []
                errors:
                  - email: not-an-email
                    code: INVALID_EMAIL
                    message: not-an-email is not a valid email address.
                warnings: []
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: contacts
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: Single upsert without an `email`.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: MISSING_EMAIL
                  type: invalid_request
                  message: email is required.
                  suggestion: Provide the contact email address.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: email
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/contacts/{email}:
    patch:
      operationId: updateContact
      tags:
        - Contacts
      summary: Update a contact
      description: "Patches one or more fields on the contact (`{ fields: { <name>: <value> } }` — core columns or custom fields). Returns `{ contact, updated }` where `updated` lists the field names that changed."
      parameters:
        - schema:
            type: string
            format: email
            description: The contact’s email address (URL-encoded). Email is the contact primary key.
            example: jane%40example.com
          required: true
          description: The contact’s email address (URL-encoded). Email is the contact primary key.
          name: email
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactsPatchRequest"
            example:
              fields:
                firstName: Janet
                plan: scale
      responses:
        "200":
          description: Patched.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactsPatchResponse"
              example:
                contact:
                  email: jane@example.com
                  firstName: Janet
                  lastName: Doe
                  subscribed: true
                  validationStatus: valid
                  verificationStatus: valid
                  suppressed: false
                  suppressedReason: null
                  createdAt: 2026-04-08T12:00:00.000Z
                  updatedAt: 2026-04-08T12:05:00.000Z
                  importId: null
                  customFields: *a17
                updated:
                  - firstName
                  - plan
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: fields
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "404":
          description: Contact not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: CONTACT_NOT_FOUND
                  type: not_found
                  message: No contact exists with email 'jane@example.com'.
                  suggestion: Upsert the contact first with POST /v1/contacts.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: email
        "422":
          description: Attempted to write a read-only core column.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: CORE_FIELD_IMMUTABLE
                  type: invalid_request
                  message: Core field 'createdAt' cannot be modified.
                  suggestion: Remove the read-only field from `fields`.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: fields.createdAt
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    delete:
      operationId: deleteContact
      tags:
        - Contacts
      summary: Delete a contact
      description: "Deletes the contact. Idempotent — an unknown email resolves with `deleted: false`. For bulk deletion use `POST /v1/contacts/batch-delete`."
      parameters:
        - schema:
            type: string
            format: email
            description: The contact’s email address (URL-encoded). Email is the contact primary key.
            example: jane%40example.com
          required: true
          description: The contact’s email address (URL-encoded). Email is the contact primary key.
          name: email
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Deleted (or already gone).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactDeleteResponse"
              example:
                email: jane@example.com
                deleted: true
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/contacts/search:
    post:
      operationId: searchContacts
      tags:
        - Contacts
      summary: Get contacts
      description: |-
        The single "Get Contacts" read. Structured search over the brand’s contacts: free-text `search`, typed `filters` (`{ field, operator, value }` combined with `logic: "and" | "or"`), `sort` + `order`, and cursor pagination. Returns `{ data, pagination }`.

        Folds the former `GET /v1/contacts` (omit all filters to list everything) and `GET /v1/contacts/{email}` (use `filters: [{ field: "email", operator: "equals", value: "…" }]`).

        Pass an optional `audienceId` to scope the search to a saved audience’s members — its stored filter is ANDed with `filters` (an unknown / cross-brand id → `400`).

        Set `count: true` to get `{ count }` instead of a page.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactsSearchRequest"
            examples:
              filtered:
                summary: Filter + sort
                value:
                  filters:
                    - field: plan
                      operator: equals
                      value: enterprise
                  sort: createdAt
                  order: desc
                  limit: 50
              count:
                summary: Count only
                value:
                  filters:
                    - field: subscribed
                      operator: equals
                      value: "true"
                  count: true
      responses:
        "200":
          description: "A page of matching contacts — or `{ count }` when `count: true`."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactsSearchSuccessResponse"
              examples:
                page:
                  summary: Result page
                  value:
                    data:
                      - *a18
                      - email: john@example.com
                        firstName: John
                        lastName: Smith
                        subscribed: true
                        validationStatus: valid
                        verificationStatus: valid
                        suppressed: false
                        suppressedReason: null
                        createdAt: 2026-04-08T12:00:00.000Z
                        updatedAt: 2026-04-08T12:05:00.000Z
                        importId: null
                        customFields:
                          plan: starter
                    pagination:
                      limit: 50
                      cursor: eyJsYXN0SWQiOiIxMjMiLCJsYXN0U29ydCI6MTcxMjU5MjAwMDAwMH0=
                      hasMore: true
                count:
                  summary: Count mode
                  value:
                    count: 1284
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: filters
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
      parameters:
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
  /v1/contacts/validate:
    post:
      operationId: validateContacts
      tags:
        - Contacts
      summary: Validate email deliverability
      description: "Batch deliverability check (up to 100 addresses) — run BEFORE importing or sending. Each address is classified `valid` (safe), `risky` (deliverable but flagged — e.g. role account, disposable, catch-all), or `invalid` (undeliverable / do-not-send), with a machine-readable `reason` and a `didYouMean` typo correction when applicable. Cost: 2 credits PER ADDRESS (`X-Credit-Cost` = 2 × the number of addresses), charged ONLY on success — if the check cannot complete for the whole batch, the call returns a retryable `503` and is NOT billed."
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactsValidateRequest"
            example:
              emails:
                - ada@gmail.com
                - temp@mailinator.com
                - admin@stripe.com
      responses:
        "200":
          description: One classification row per input address.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactsValidateResponse"
              example:
                data:
                  - email: ada@gmail.com
                    valid: true
                    status: valid
                  - email: temp@mailinator.com
                    valid: false
                    status: invalid
                    reason: undeliverable
                  - email: ada@gmial.com
                    valid: false
                    status: risky
                    reason: unknown
                    didYouMean: ada@gmail.com
                  - email: admin@stripe.com
                    valid: false
                    status: risky
                    reason: role_address
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: emails
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
      parameters:
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
  /v1/contacts/import-csv:
    post:
      operationId: importContactsCsv
      tags:
        - Contacts
      summary: Bulk-import contacts from CSV
      description: 'Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to a field of the same name (`email` is required); pass `mapping` to remap columns explicitly. Rows with a missing/invalid email are SKIPPED (counted in `summary.skipped`), not errored; disposable-domain rows are imported with `validationStatus: "risky"` (deliverable but flagged). Returns the same `{ summary, fieldsCreated, errors, warnings }` as batch-create — `207` when some rows fail validation.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactsImportCsvRequest"
            example:
              csv: |-
                email,firstName,lastName
                ada@example.com,Ada,Lovelace
                grace@example.com,Grace,Hopper
              mapping:
                email: email
                firstName: firstName
                lastName: lastName
      responses:
        "200":
          description: Import summary (all rows valid).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactsImportCsvResponse"
              example:
                summary:
                  inserted: 2
                  updated: 0
                  failed: 0
                  skipped: 0
                fieldsCreated: []
                errors: []
                warnings: []
        "207":
          description: Partial success — some rows failed validation.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                type: object
                properties:
                  summary:
                    type: object
                    properties:
                      inserted:
                        type: integer
                        minimum: 0
                      updated:
                        type: integer
                        minimum: 0
                      failed:
                        type: integer
                        minimum: 0
                      skipped:
                        type: integer
                        minimum: 0
                    required:
                      - inserted
                      - updated
                      - failed
                      - skipped
                    additionalProperties: false
                  fieldsCreated:
                    type: array
                    items:
                      type: string
                  errors:
                    type: array
                    items:
                      type: object
                      properties:
                        email:
                          type: string
                        code:
                          type: string
                        message:
                          type: string
                      required:
                        - email
                        - code
                        - message
                      additionalProperties: false
                  warnings:
                    type: array
                    items:
                      type: object
                      properties:
                        code:
                          type: string
                          minLength: 1
                        field:
                          type: string
                          minLength: 1
                        message:
                          type: string
                          minLength: 1
                        from:
                          type: string
                          minLength: 1
                        to:
                          type: string
                          minLength: 1
                        original:
                          type: string
                          minLength: 1
                        normalized:
                          type: string
                          minLength: 1
                      required:
                        - code
                        - message
                      additionalProperties: false
                  validation:
                    type: object
                    properties:
                      valid:
                        type: integer
                        minimum: 0
                      risky:
                        type: integer
                        minimum: 0
                      invalid:
                        type: integer
                        minimum: 0
                      unscored:
                        type: integer
                        minimum: 0
                    required:
                      - valid
                      - risky
                      - invalid
                      - unscored
                    additionalProperties: false
                  validationJobId:
                    type: string
                required:
                  - summary
                  - fieldsCreated
                  - errors
                  - warnings
                additionalProperties: false
              example:
                summary:
                  inserted: 1
                  updated: 0
                  failed: 1
                  skipped: 2
                fieldsCreated: []
                errors:
                  - email: dupe@example.com
                    code: DUPLICATE_EMAILS_IN_BATCH
                    message: Email 'dupe@example.com' appears 2 times in batch.
                warnings: []
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: csv
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
      parameters:
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
  /v1/contacts/batch-delete:
    post:
      operationId: batchDeleteContacts
      tags:
        - Contacts
      summary: Batch-delete contacts
      description: Deletes up to 1000 contacts by email. Returns the deleted count plus `notFound[]` for emails that had no contact.
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactsBatchDeleteRequest"
            example:
              emails:
                - jane@example.com
                - gone@example.com
      responses:
        "200":
          description: Batch delete applied.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactsBatchDeleteResponse"
              example:
                deleted: 1
                notFound:
                  - gone@example.com
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: emails
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/fields:
    get:
      operationId: listContactFields
      tags:
        - Contact Fields
      summary: List contact fields
      description: "Lists core contact columns and custom field definitions under `{ data, pagination }`. Use the field names in audience filters, contact search, and `{{ field | fallback }}` merge tags. Add `?include=coverage` to decorate each row with fill stats — the % of contacts holding a non-empty value plus the most common values (sampled; `approximate: true` on large populations) — and optionally `audienceId` to scope those stats to one saved audience. Check coverage before personalizing on a field so most recipients see a real value, not the fallback."
      parameters:
        - name: include
          in: query
          required: false
          description: "Opt-in expansion: `coverage` adds per-field fill stats (percent of contacts with a non-empty value + top values)."
          schema:
            type: string
            enum:
              - coverage
        - name: audienceId
          in: query
          required: false
          description: Scope `include=coverage` stats to one saved audience (`404 AUDIENCE_NOT_FOUND` on an unknown / cross-brand id). Ignored without the include.
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - *a7
        - *a8
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: A page of field definitions.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FieldsGetResponse"
              example:
                data:
                  - fieldName: email
                    fieldType: string
                    label: Email
                    isCore: true
                    isFilterable: true
                    isSortable: true
                    isSearchable: true
                  - fieldName: plan
                    fieldType: string
                    label: Plan
                    isCore: false
                    isFilterable: true
                    isSortable: true
                    isSearchable: false
                    coverage:
                      percent: 62
                      approximate: true
                      topValues:
                        - value: scale
                          count: 610
                          percent: 51
                        - value: starter
                          count: 420
                          percent: 35
                      dominantValue: scale
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: limit
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    post:
      operationId: createContactField
      tags:
        - Contact Fields
      summary: Create a contact field
      description: 'Creates a custom field definition (`{ fieldName, fieldType: "string" | "number" | "date" | "bool" }`). Returns `201` with the bare definition. (Contact upserts also auto-create unknown fields — explicit creation is for pinning the type up front.)'
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FieldsPostRequest"
            example:
              fieldName: plan
              fieldType: string
      responses:
        "201":
          description: Created.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactFieldDefinition"
              example:
                fieldName: plan
                fieldType: string
                label: Plan
                isCore: false
                isFilterable: true
                isSortable: true
                isSearchable: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: fieldType
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "409":
          description: The field already exists with a different `fieldType` — redefinition is rejected to avoid corrupting stored values (re-creating with the SAME type is idempotent). An idempotency-key replay with a different body also returns `409`.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: FIELD_TYPE_MISMATCH
                  type: conflict
                  message: Field 'plan' is type 'string' but received 'number'.
                  suggestion: Send a value that matches the field definition, or update the field definition first.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: plan
        "422":
          description: The field name collides with a core column.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: CORE_FIELD_IMMUTABLE
                  type: invalid_request
                  message: "'email' is a core field and cannot be redefined."
                  suggestion: Pick a different fieldName.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: fieldName
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/fields/{fieldName}:
    delete:
      operationId: deleteContactField
      tags:
        - Contact Fields
      summary: Delete a contact field
      description: "Deletes a custom field definition (core columns cannot be deleted — `422 CORE_FIELD_IMMUTABLE`). Idempotent — an unknown name resolves with `deleted: false`."
      parameters:
        - schema:
            type: string
            minLength: 1
            description: The custom field name (URL-encoded when needed).
            example: plan
          required: true
          description: The custom field name (URL-encoded when needed).
          name: fieldName
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Deleted (or already gone).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FieldsDeleteResponse"
              example:
                fieldName: plan
                deleted: true
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "422":
          description: Core columns cannot be deleted.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: CORE_FIELD_IMMUTABLE
                  type: invalid_request
                  message: "'email' is a core field and cannot be deleted."
                  suggestion: Only custom fields can be deleted.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: fieldName
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/audiences:
    get:
      operationId: listAudiences
      tags:
        - Audiences
      summary: Get audiences
      description: "Unified audience read. Omit `audienceId` to LIST the brand’s saved audiences under `{ data, pagination }`. Each row carries its contact `filters`, the cached member `count`, and ISO timestamps. An audience is the recipient target for `POST /v1/sends`. Pass `?audienceId=` to fetch ONE — returns `{ data: [row] }` (no `pagination`), `404 AUDIENCE_NOT_FOUND` on an unknown / cross-brand id. Add `?include=count` (detail only) to replace the cached `count` with a freshly computed member total."
      parameters:
        - name: audienceId
          in: query
          required: false
          description: "Fetch a single audience by id (detail mode → `{ data: [row] }`). Omit to list."
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: include
          in: query
          required: false
          description: "Detail-only expansions (comma-separated): `count` recomputes the live member total; `build` attaches the latest event-cohort build status for audiences created via `POST /v1/audiences/from-events`. Rejected without `audienceId`."
          schema:
            type: string
            example: count,build
        - *a7
        - *a8
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "A page of audiences (list mode), or `{ data: [row] }` (detail mode)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AudiencesListResponse"
              example:
                data:
                  - &a19
                    audienceId: jn7a8w4q8m9k2p1x7c3b5v6n9h7s2d4f
                    audienceName: Nordic Founders
                    filters: &a21
                      filters:
                        - field: country
                          operator: equals
                          value: NO
                      logicalOperator: and
                    count: 1284
                    createdAt: 2026-04-08T12:34:56.789Z
                    updatedAt: 2026-04-08T12:34:56.789Z
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: limit
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `audiences` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: audiences
        "404":
          description: Audience not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: &a20
                error:
                  code: AUDIENCE_NOT_FOUND
                  type: not_found
                  message: The requested audience 'aud_xxx' was not found.
                  suggestion: List audiences with GET /v1/audiences.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: audienceId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    post:
      operationId: createAudience
      tags:
        - Audiences
      summary: Create an audience
      description: 'Creates a saved audience from a name + filter set (`{ filters: [{ field, operator, value? }], logicalOperator: "and" | "or" }`). Returns `201` with the bare audience row. An `email in [...]` clause listing more than 100 addresses is converted automatically: a fresh date custom field is stamped on the listed EXISTING contacts and the stored filter becomes `customFields.<field> is_not_empty` (a snapshot — addresses with no contact record are skipped), reported back as `emailListMaterializations`; 10,000 addresses max per clause.'
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AudiencesPostRequest"
            example:
              name: Nordic Founders
              filters:
                filters:
                  - field: country
                    operator: equals
                    value: NO
                logicalOperator: and
      responses:
        "201":
          description: Created.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AudienceWriteResponse"
              example: *a19
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: filters
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `audiences` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: audiences
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/audiences/from-events:
    post:
      operationId: createAudienceFromEvents
      tags:
        - Audiences
      summary: Create an audience from analytics events
      description: "Creates a frozen audience snapshot from the same membership filters as `/events`: 1–10 canonical event types, an absolute window up to 90 days, optional send/email ids, multi-select automation/audience ids, recipient include/exclude rules, and the machine-click policy. Every call generates a unique date field; each matching existing contact stores its latest matching-event timestamp. Returns `201` immediately with `materializationStatus: pending` plus build progress. The audience is unavailable for campaign, smart-send, and automation delivery until the status becomes `ready`. Failed/partial/stale builds remain non-sendable and partial values are cleaned. Poll `GET /v1/audiences?audienceId=…&include=build`."
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AudiencesFromEventsRequest"
            example:
              cohort:
                eventTypes:
                  - opened
                from: 2026-07-04T00:00:00.000Z
                to: 2026-08-03T00:00:00.000Z
      responses:
        "201":
          description: Created. The audience exists immediately; `build` tracks the background stamping run.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AudiencesFromEventsResponse"
              example:
                audienceId: jn7a8w4q8m9k2p1x7c3b5v6n9h7s2d4f
                audienceName: Openers · Jul 4 – Aug 3, 2026
                filters:
                  filters:
                    - field: customFields.openedJul4Aug3
                      operator: is_not_empty
                      type: date
                  logicalOperator: and
                count: 0
                createdAt: 2026-04-08T12:34:56.789Z
                updatedAt: 2026-04-08T12:34:56.789Z
                materializationStatus: pending
                build:
                  jobId: kh7c2m4q8n9w2p1x7c3b5v6n9h7s2d4f
                  status: pending
                  cohort:
                    eventTypes:
                      - opened
                    from: 2026-07-04T00:00:00.000Z
                    to: 2026-08-03T00:00:00.000Z
                  field:
                    key: openedJul4Aug3
                    label: Opened Jul 4 – Aug 3
                    type: date
                  counts:
                    eventsScanned: 0
                  enqueuedAt: 2026-08-03T12:00:00.000Z
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: cohort
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `contacts` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: contacts
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/audiences/{audienceId}:
    patch:
      operationId: updateAudience
      tags:
        - Audiences
      summary: Update an audience
      description: "Updates `name` and/or `filters` (at least one required). Pass the latest row’s `updatedAt` as `expectedUpdatedAt` to reject stale read-modify-write edits. Returns the bare updated row. Replacement filters follow the same email-list rule as create: an `email in [...]` clause over 100 addresses is converted into a stamped custom-field snapshot (a fresh field per update), reported as `emailListMaterializations`."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Audience id (opaque Convex document id) returned by `POST /v1/audiences` and listed by `GET /v1/audiences`.
            example: jn7a8w4q8m9k2p1x7c3b5v6n9h7s2d4f
          required: true
          description: Audience id (opaque Convex document id) returned by `POST /v1/audiences` and listed by `GET /v1/audiences`.
          name: audienceId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AudiencesPatchRequest"
            example:
              name: Nordic Founders (active)
      responses:
        "200":
          description: Updated.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AudienceWriteResponse"
              example: *a19
        "400":
          description: Strict-body violation or no editable field supplied (at least one of `name` / `filters` is required).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: name
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `audiences` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: audiences
        "404":
          description: Audience not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a20
        "409":
          description: The `expectedUpdatedAt` precondition is stale; reload the audience before retrying.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: AUDIENCE_EDIT_CONFLICT
                  type: conflict
                  message: This audience changed while it was being edited.
                  suggestion: Reload the latest audience filters and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    delete:
      operationId: deleteAudience
      tags:
        - Audiences
      summary: Delete an audience
      description: "Deletes the audience. Idempotent — an unknown id resolves with `deleted: false`."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Audience id (opaque Convex document id) returned by `POST /v1/audiences` and listed by `GET /v1/audiences`.
            example: jn7a8w4q8m9k2p1x7c3b5v6n9h7s2d4f
          required: true
          description: Audience id (opaque Convex document id) returned by `POST /v1/audiences` and listed by `GET /v1/audiences`.
          name: audienceId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Deleted (or already gone).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AudiencesDeleteResponse"
              example:
                audienceId: jn7a8w4q8m9k2p1x7c3b5v6n9h7s2d4f
                deleted: true
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `audiences` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: audiences
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/audiences/{audienceId}/duplicate:
    post:
      operationId: duplicateAudience
      tags:
        - Audiences
      summary: Duplicate an audience
      description: Creates a deterministic copy of the saved audience’s live filters with a server-generated “(copy)” name. Contacts are not copied; both audiences resolve against the same contact records.
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Audience id (opaque Convex document id) returned by `POST /v1/audiences` and listed by `GET /v1/audiences`.
            example: jn7a8w4q8m9k2p1x7c3b5v6n9h7s2d4f
          required: true
          description: Audience id (opaque Convex document id) returned by `POST /v1/audiences` and listed by `GET /v1/audiences`.
          name: audienceId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "201":
          description: Copied.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Audience"
              example:
                audienceId: mh8b9x5r9n1k3p2y8c4d6w7q1j9t3f5g
                audienceName: Nordic Founders (copy)
                filters: *a21
                count: 1284
                createdAt: 2026-04-08T12:34:56.789Z
                updatedAt: 2026-04-08T12:34:56.789Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `audiences` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: audiences
        "404":
          description: Audience not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a20
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/domains:
    get:
      operationId: listDomains
      tags:
        - Domains
      summary: Get domains
      description: "Unified domain read. Omit `domainId` to LIST the brand’s sending domains under `{ data, pagination }` — ALL lifecycle states by default (so callers mid-verification can read `pending` rows + their DNS `records`); pass `?sendableOnly=true` for only verified, send-ready domains (the set valid for `POST /v1/sends` and automation `sendEmail` nodes). Pass `?sendingPurpose=marketing` to hide transactional domains (automations and campaigns require marketing). Pass `?domainId=` to fetch ONE domain — returns `{ data: [row] }` (no `pagination`), `404 DOMAIN_NOT_FOUND` on an unknown / cross-brand id."
      parameters:
        - name: domainId
          in: query
          required: false
          description: "Fetch a single domain by id (detail mode → `{ data: [row] }`). Omit to list."
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: sendableOnly
          in: query
          required: false
          description: List mode only — when `true`, only verified send-ready domains.
          schema:
            type: string
            enum:
              - "true"
              - "false"
        - name: sendingPurpose
          in: query
          required: false
          description: List mode only — filter by `marketing` or `transactional`. Use marketing for campaigns and automations.
          schema:
            type: string
            enum:
              - marketing
              - transactional
        - *a7
        - *a8
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: "A page of domains (list mode), or `{ data: [row] }` (detail mode)."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DomainsListResponse"
              example:
                data:
                  - &a22
                    domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                    domainUrl: https://send.example.com
                    name: send.example.com
                    region: us-east-1
                    status: pending
                    sendingEnabled: true
                    sendable: false
                    sendingPurpose: marketing
                    records: &a24
                      - record: DKIM
                        name: resend._domainkey
                        type: TXT
                        ttl: Auto
                        status: pending
                        value: p=MIGfMA0...
                    createdAt: 2026-04-08T12:34:56.789Z
                    updatedAt: 2026-04-08T12:34:56.789Z
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: sendableOnly
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `domains` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: domains
        "404":
          description: Domain not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: &a23
                error:
                  code: DOMAIN_NOT_FOUND
                  type: not_found
                  message: The requested domain 'dom_xxx' was not found.
                  suggestion: List domains with GET /v1/domains.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: domainId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    post:
      operationId: addDomain
      tags:
        - Domains
      summary: Add a domain
      description: 'Registers a sending domain with the provider. Optional `sendingPurpose` is `marketing` (default; campaigns and automations) or `transactional` (API/MCP inline `to` only). Returns `201` with the bare row in `status: "pending"` plus the DNS `records` to publish. Once the records are live, call `POST /v1/domains/{domainId}/verify` until `sendable: true`.'
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DomainsPostRequest"
            example:
              name: send.example.com
      responses:
        "201":
          description: Added — publish the returned DNS records, then verify.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Domain"
              example: *a22
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: name
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `domains` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: domains
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/domains/{domainId}:
    patch:
      operationId: updateDomain
      tags:
        - Domains
      summary: Update domain settings
      description: "Updates sender defaults (`defaultSenderName`, `defaultFromEmail`, `defaultReplyToEmail`) and/or `sendingPurpose` — at least one required. Live gates fail closed if a campaign or automation still points at a transactional domain. Verification is its own action: `POST /v1/domains/{domainId}/verify`. Returns the bare updated row."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Domain id (opaque Convex document id) returned by `POST /v1/domains` and listed by `GET /v1/domains`.
            example: kx7bkh53hasmfeh5kd7sqgykt187g8ww
          required: true
          description: Domain id (opaque Convex document id) returned by `POST /v1/domains` and listed by `GET /v1/domains`.
          name: domainId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DomainsPatchRequest"
            example:
              defaultSenderName: Brew
              defaultFromEmail: hello@send.example.com
      responses:
        "200":
          description: Updated.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Domain"
              example: *a22
        "400":
          description: Strict-body violation or no editable field supplied (at least one of `defaultSenderName` / `defaultFromEmail` / `defaultReplyToEmail` / `sendingPurpose`).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: defaultSenderName
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `domains` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: domains
        "404":
          description: Domain not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a23
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    delete:
      operationId: deleteDomain
      tags:
        - Domains
      summary: Delete a domain
      description: "Removes the domain from the provider and deletes the local row. Idempotent — an unknown id resolves with `deleted: false`."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Domain id (opaque Convex document id) returned by `POST /v1/domains` and listed by `GET /v1/domains`.
            example: kx7bkh53hasmfeh5kd7sqgykt187g8ww
          required: true
          description: Domain id (opaque Convex document id) returned by `POST /v1/domains` and listed by `GET /v1/domains`.
          name: domainId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: Deleted (or already gone).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DomainsDeleteResponse"
              example:
                domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                deleted: true
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `domains` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: domains
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/domains/{domainId}/verify:
    post:
      operationId: verifyDomain
      tags:
        - Domains
      summary: Verify a domain
      description: "Re-checks the DNS records with the provider and refreshes the row. Empty body. Safe to poll — keep calling until `sendable: true` (DNS propagation can take minutes to hours). Returns the bare refreshed row."
      parameters:
        - *a1
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Domain id (opaque Convex document id) returned by `POST /v1/domains` and listed by `GET /v1/domains`.
            example: kx7bkh53hasmfeh5kd7sqgykt187g8ww
          required: true
          description: Domain id (opaque Convex document id) returned by `POST /v1/domains` and listed by `GET /v1/domains`.
          name: domainId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: The refreshed domain row.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Domain"
              example:
                domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                domainUrl: https://send.example.com
                name: send.example.com
                region: us-east-1
                status: verified
                sendingEnabled: true
                sendable: true
                sendingPurpose: marketing
                records: *a24
                createdAt: 2026-04-08T12:34:56.789Z
                updatedAt: 2026-04-08T12:34:56.789Z
                verifiedAt: 2026-04-08T13:00:00.000Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `domains` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: domains
        "404":
          description: Domain not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a23
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/domains/{domainId}/health:
    get:
      operationId: getDomainHealth
      tags:
        - Domains
      summary: Get domain health
      description: "The domain's deliverability health in one FREE read: a `verdict` (`healthy` / `at_risk` / `critical`) with actionable `signals`, DNS/auth state incl. DMARC, active percentage-based gradual sends + recent UTC-day volume, general bounce/complaint reporting, workspace reputation, and inbox-placement history. No bounce or complaint threshold is attached to a gradual-send configuration."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Domain id (opaque Convex document id) returned by `POST /v1/domains` and listed by `GET /v1/domains`.
            example: kx7bkh53hasmfeh5kd7sqgykt187g8ww
          required: true
          description: Domain id (opaque Convex document id) returned by `POST /v1/domains` and listed by `GET /v1/domains`.
          name: domainId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: The aggregate health report.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DomainHealth"
              example:
                domainId: kx7bkh53hasmfeh5kd7sqgykt187g8ww
                name: send.example.com
                status: verified
                sendable: true
                verdict: at_risk
                authentication:
                  spf: verified
                  dkim: verified
                  dmarc: missing
                tracking:
                  linksStatus: live
                  openTracking: true
                  clickTracking: true
                warmup:
                  - sendId: snd_x1
                    currentTranche: 3
                    sentSoFar: 175
                    rampEndsAt: 2026-07-15T00:00:00.000Z
                dailyVolume:
                  - day: 2026-07-11
                    sent: 50
                  - day: 2026-07-12
                    sent: 63
                domainActivity:
                  sampled: true
                  sampleSendCount: 12
                  sentCount: 2400
                  bouncedCount: 31
                  complainedCount: 1
                  bounceRate: 0.0129
                  complaintRate: 0.0004
                orgReputation:
                  scope: org
                  totalSent: 18250
                  bounceRate: 0.011
                  complaintRate: 0.0003
                recentPlacementTests:
                  - testId: ibp_2f1c9d8a
                    emailId: eml_welcome
                    status: completed
                    overall:
                      total: 41
                      inbox: 33
                      spam: 8
                      missing: 0
                      pending: 0
                    authentication:
                      spf: pass
                      dkim: pass
                      dmarc: pass
                    spamFilterFlagged: false
                    createdAt: 2026-07-13T17:00:00.000Z
                signals:
                  - id: dmarc_missing
                    severity: warning
                    summary: No DMARC record is configured for this domain.
                    suggestion: 'Add a TXT record: _dmarc TXT "v=DMARC1; p=reject; rua=mailto:dmarc@send.example.com" — Gmail/Yahoo bulk-sender rules require DMARC, and it blocks spoofing.'
                checkedAt: 2026-07-13T18:00:00.000Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `domains` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: domains
        "404":
          description: Domain not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a23
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/templates:
    get:
      operationId: listTemplates
      tags:
        - Templates
      summary: List templates
      description: Lists public email templates under `{ data, pagination }`. Each row is FULL — it carries the rendered `html` + `previewImage` plus the display metadata (`title`, `category`, `brand`, `updatedAt`), so you never need a follow-up get-one round-trip. Supports exact `?brand=` and `?category=` filters and a lightweight `?semantic=` text filter. Templates are organization-wide references (use one as `referenceEmailId` on `POST /v1/emails`).
      parameters:
        - schema:
            type: string
            minLength: 1
          required: false
          name: brand
          in: query
        - schema:
            type: string
            minLength: 1
          required: false
          name: category
          in: query
        - schema:
            type: string
            minLength: 1
          required: false
          name: semantic
          in: query
        - schema:
            anyOf:
              - type: number
              - type: string
          required: false
          name: limit
          in: query
        - schema:
            type: string
            minLength: 1
            maxLength: 512
          required: false
          name: cursor
          in: query
      responses:
        "200":
          description: A page of templates matching the filters.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplatesListResponse"
              example:
                data:
                  - emailId: seed-vercel-newsletter
                    title: Vercel Newsletter
                    category: newsletter
                    brand: vercel.com
                    html: <!DOCTYPE html><html><body>…</body></html>
                    previewImage: https://storage.example.com/templates/seed.png
                    updatedAt: 2026-04-08T00:00:00.000Z
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: brand
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/brand:
    get:
      operationId: getBrand
      tags:
        - Brand
      summary: Get the brand bound to this API key
      description: |-
        Returns `{ brand }` — the single brand bound to the API key. Check `ready` (`status === "completed"`) before calling `POST /v1/emails`, which returns `422 BRAND_NOT_READY` until brand extraction finishes.

        Embed the design context in the same call with `?include=identity,emailDesign,imageStyle,logos` (comma-separated). `identity` is the structured brand facts; `emailDesign` / `imageStyle` are the markdown design system the email agent follows; `logos` is the CDN logo set. The paginated image library is a separate read (`GET /v1/brand/images`).
      parameters:
        - schema:
            type: string
          required: false
          name: include
          in: query
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: The brand bound to this API key, plus any sub-resources named in `?include=`.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrandGetResponse"
              example:
                brand:
                  brandId: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
                  domain: vercel.com
                  status: completed
                  ready: true
                  createdAt: 2026-04-08T12:00:00.000Z
                  updatedAt: 2026-04-08T12:05:00.000Z
                identity:
                  brandName: Vercel
                  tagline: Develop. Preview. Ship.
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: include
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "404":
          description: The brand bound to this API key was not found.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: BRAND_NOT_FOUND
                  type: not_found
                  message: The brand bound to this API key was not found.
                  suggestion: Verify in the dashboard that the brand bound to this API key still exists.
                  docs: https://docs.brew.new/api-reference/api/errors
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
    patch:
      operationId: updateBrand
      tags:
        - Brand
      summary: Update brand identity + design system
      description: Partial update of the writable design artifacts in one call. `identity` shallow-merges the provided fields; `emailDesign` / `imageStyle` replace the markdown design-system documents the email agent follows. Provide at least one. Returns the touched fields in the `GET /v1/brand` shape.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BrandPatchRequest"
            examples:
              identity:
                summary: Merge identity fields
                value:
                  identity:
                    tagline: Complete user management for modern apps.
              design:
                summary: Replace the email-design house style
                value:
                  emailDesign: |-
                    # email-design.md

                    Updated house style…
      responses:
        "200":
          description: The updated brand (only the touched fields are echoed).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrandGetResponse"
              example:
                brand:
                  brandId: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
                  domain: vercel.com
                  status: completed
                  ready: true
                identity:
                  brandName: Vercel
                  tagline: Complete user management for modern apps.
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: identity
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
      parameters:
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
  /v1/brand/images:
    get:
      operationId: getBrandImages
      tags:
        - Brand
      summary: Get brand images
      description: The brand’s image library — dual-mode. Pass `?q=` for SEMANTIC search (the query is embedded + vector-searched over the brand’s indexed assets; `?type` and `?aspectRatio` narrow it) — this path is **credit-metered** (`402 INSUFFICIENT_CREDITS` when out of credits). Omit `?q=` to BROWSE the stored harvested + generated library (free), optionally filtered by `?type` / `?aspectRatio`. Either way returns `{ data, pagination }` of images with a description + dimensions. (The smaller `identity` / `emailDesign` / `imageStyle` / `logos` sub-resources embed into `GET /v1/brand?include=…`; images stay separate because they paginate.)
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 500
          required: false
          name: q
          in: query
        - schema:
            type: string
            minLength: 1
            maxLength: 40
          required: false
          name: type
          in: query
        - schema:
            type: string
            minLength: 1
            maxLength: 20
          required: false
          name: aspectRatio
          in: query
        - schema:
            anyOf:
              - type: number
              - type: string
          required: false
          name: limit
          in: query
        - schema:
            type: string
            minLength: 1
            maxLength: 512
          required: false
          name: cursor
          in: query
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: A page of brand images (semantic results when `?q=`).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrandImagesResponse"
              example:
                data:
                  - url: https://cdn.brew.new/cnt/abc.png
                    description: Clerk user-profile component
                    width: 1056
                    height: 1002
                pagination:
                  limit: 20
                  cursor: null
                  hasMore: false
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
  /v1/brands:
    get:
      operationId: listBrands
      tags:
        - Brands
      summary: List the brands this credential can reach
      description: |-
        Organization-scoped credentials see every brand in the organization; a brand-scoped credential sees exactly the one brand it is bound to.

        This is how an organization-scoped credential discovers the ids it passes in `X-Brand-Id` on every other endpoint.
      parameters:
        - *a7
        - *a8
        - schema:
            type: string
            enum:
              - extracting
              - completed
              - failed
              - deleting
          required: false
          name: status
          in: query
        - schema:
            anyOf:
              - type: number
              - type: string
          required: false
          name: limit
          in: query
        - schema:
            type: string
            minLength: 1
            maxLength: 512
          required: false
          name: cursor
          in: query
      responses:
        "200":
          description: The brands this credential can reach.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrandsListResponse"
              example:
                data:
                  - brandId: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
                    domain: vercel.com
                    status: completed
                    ready: true
                    createdAt: 2026-04-08T12:00:00.000Z
                    updatedAt: 2026-04-08T12:05:00.000Z
                  - brandId: kx9d1p2qbrxy4nkm55ftz3lmvn21abcd
                    domain: acme.com
                    status: extracting
                    ready: false
                    progress: 0
                    phase: analyzing
                    createdAt: 2026-04-08T12:00:00.000Z
                    updatedAt: 2026-04-08T12:00:00.000Z
                pagination:
                  limit: 100
                  cursor: null
                  hasMore: false
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: status
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    post:
      operationId: createBrand
      tags:
        - Brands
      summary: Create a brand and start its extraction
      description: |-
        Starts an asynchronous brand extraction that crawls the site and builds the design system. Returns `201` immediately with `status: "extracting"` — poll `GET /v1/brands/{brandId}` until `ready` is `true` (typically 1–3 minutes) before calling `POST /v1/emails`, which returns `422 BRAND_NOT_READY` until then.

        Requires an ORGANIZATION-scoped credential (`403 ORG_SCOPE_REQUIRED` otherwise) and the `brands` scope, which is NOT implied by `emails`.

        Extraction requires a non-empty credit balance but is not itself charged to your credits.
      parameters:
        - *a1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BrandsCreateRequest"
            example:
              url: acme.com
              instructions: Use the product pages for tone. Primary brand color is the deep navy in the header.
      responses:
        "201":
          description: The brand was created and extraction started. Poll `extraction.statusUrl`.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrandsCreateResponse"
              example:
                brand:
                  brandId: kx9d1p2qbrxy4nkm55ftz3lmvn21abcd
                  domain: acme.com
                  status: extracting
                  ready: false
                  progress: 0
                  phase: analyzing
                  createdAt: 2026-04-08T12:00:00.000Z
                  updatedAt: 2026-04-08T12:00:00.000Z
                extraction:
                  chatId: 6f1c2b9e-6c2a-4a2e-9f5f-2b7d9a3e4c11
                  statusUrl: /v1/brands/kx9d1p2qbrxy4nkm55ftz3lmvn21abcd
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: url
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: The organization is at its plan brand limit, or has no credits.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: BRAND_LIMIT_REACHED
                  type: payment_required
                  message: Brand limit reached on the Free plan (3 brand workspaces). Upgrade your plan to add more brand workspaces.
                  suggestion: Delete an unused brand, or upgrade the plan to add more brands.
                  docs: https://docs.brew.new/api-reference/api/errors
        "403":
          description: A brand-scoped credential cannot create brands, or the key lacks the `brands` scope.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              examples:
                organizationScopeRequired:
                  summary: The credential is bound to one brand
                  value:
                    error:
                      code: ORG_SCOPE_REQUIRED
                      type: authorization_error
                      message: Creating a brand acts on the organization, not a single brand, so it requires an organization-scoped credential.
                      suggestion: Create an organization-scoped API key in Settings → API, or connect MCP at the organization level.
                      docs: https://docs.brew.new/api-reference/api/authentication
                insufficientPermissions:
                  summary: The credential lacks the brands permission
                  value:
                    error:
                      code: INSUFFICIENT_PERMISSIONS
                      type: authorization_error
                      message: The caller does not have the required permission.
                      suggestion: Use an organization-scoped API key with the brands permission.
                      docs: https://docs.brew.new/api-reference/api/authentication
                      param: brands
        "409":
          description: The organization already has an active brand for that domain.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: BRAND_DOMAIN_CONFLICT
                  type: conflict
                  message: A brand for acme.com already exists in this organization.
                  suggestion: This organization already has a brand for that domain — find it with GET /v1/brands.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: url
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/brands/{brandId}:
    get:
      operationId: getBrandById
      tags:
        - Brands
      summary: Get one brand’s lifecycle state
      description: |-
        The polling endpoint for `POST /v1/brands`. Reports `status`, `progress` and `phase` while extracting, and `error` when extraction failed. Terminal states are `completed` and `failed`.

        For the brand’s DESIGN CONTEXT (identity, markdown design system, logos) use `GET /v1/brand` instead.
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: Brand id (opaque Convex document id) returned by `POST /v1/brands` and listed by `GET /v1/brands`.
            example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
          required: true
          description: Brand id (opaque Convex document id) returned by `POST /v1/brands` and listed by `GET /v1/brands`.
          name: brandId
          in: path
      responses:
        "200":
          description: The brand.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrandGetByIdResponse"
              example:
                brand:
                  brandId: kx9d1p2qbrxy4nkm55ftz3lmvn21abcd
                  domain: acme.com
                  status: extracting
                  ready: false
                  progress: 0
                  phase: analyzing
                  createdAt: 2026-04-08T12:00:00.000Z
                  updatedAt: 2026-04-08T12:00:00.000Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "404":
          description: No such brand in this organization — or one this credential cannot reach. Unknown, cross-organization and mid-deletion brands are deliberately indistinguishable.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: BRAND_NOT_FOUND
                  type: not_found
                  message: The brand 'kx9d1p2qbrxy4nkm55ftz3lmvn21abcd' was not found in this organization.
                  suggestion: List the brands this credential can reach with GET /v1/brands.
                  docs: https://docs.brew.new/api-reference/api/errors
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/content/generate-image:
    post:
      operationId: generateContentImage
      tags:
        - Content
      summary: Generate an image
      description: "Generates an image via the Brew AI image pipeline. `text-to-image` (default) creates from a prompt; `image-editing` edits `image1` (required) guided by the prompt. Returns a CDN-hosted URL. Usage-metered: charges the actual image gateway cost (no fixed price)."
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        description: Prompt + optional mode / aspect ratio / source images.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContentGenerateImageRequest"
      responses:
        "200":
          description: The operation result.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContentImageResponse"
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: The source image/video could not be processed (unreachable URL, non-decodable media, or upload failure).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: &a25
                error:
                  code: CONTENT_OPERATION_FAILED
                  type: invalid_request
                  message: "The optimize operation could not be completed: the image could not be fetched, decoded, or uploaded."
                  suggestion: Ensure the source URL is a publicly reachable image/video and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: imageUrl
                  details:
                    operation: optimize
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
  /v1/content/gif:
    post:
      operationId: contentGif
      tags:
        - Content
      summary: Generate a GIF
      description: "Produces a looping animated GIF (5-second source clip), routed by the `from` discriminator: `prompt` generates an on-brand still then animates it, `image` animates a source image (both via the AI gif workflow), and `video` converts a source MP4. Aspect ratio is one of `16:9`, `9:16`, `1:1`. Returns CDN-hosted `gifUrl` (plus `videoUrl` and motion metadata for the AI sources). Credit-metered (fixed cost: prompt 20, image 10, video 10)."
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        description: 'A `from` discriminator: `{ from:"prompt", prompt, … }`, `{ from:"image", imageUrl, … }`, or `{ from:"video", videoUrl, … }`.'
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContentGifRequest"
      responses:
        "200":
          description: The operation result.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContentGifResponse"
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: The source image/video could not be processed (unreachable URL, non-decodable media, or upload failure).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a25
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
  /v1/content/transform:
    post:
      operationId: contentTransform
      tags:
        - Content
      summary: Transform an image
      description: "Deterministic image transform routed by the `operation` discriminator: `optimize` rehosts a palette PNG (resize ≤1200px), `resize` produces exact dimensions via the vision-guided fal pipeline (Sharp cover-crop fallback), `remove_background` returns a transparent PNG cutout (Bria RMBG 2.0). Returns the CDN-hosted `url` + dimensions. Credit-metered (fixed cost: optimize 1, resize 2, remove_background 1)."
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        description: 'An `operation` discriminator: `{ operation:"optimize", imageUrl }`, `{ operation:"resize", imageUrl, width, height, … }`, or `{ operation:"remove_background", imageUrl }`.'
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContentTransformRequest"
      responses:
        "200":
          description: The operation result.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContentTransformResponse"
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: The source image/video could not be processed (unreachable URL, non-decodable media, or upload failure).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a25
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
  /v1/content/html-to-png:
    post:
      operationId: contentHtmlToPng
      tags:
        - Content
      summary: Render HTML to a PNG
      description: Renders an HTML document to a PNG screenshot hosted on the CDN. Credit-metered (fixed cost).
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        description: Full `html` + optional viewport width / max height.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContentHtmlToPngRequest"
      responses:
        "200":
          description: The operation result.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContentPngResponse"
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "402":
          description: "The org's remaining credit balance is below what this operation requires. Credit cost is published PER-OPERATION (see `GET /v1/help`): content/media operations charge a flat cost, while AI generation (email generate/edit, image generation) is usage-metered — charged by actual model usage rather than a flat price. `details.cost` carries the amount the runtime required for THIS call. Check your balance up front via `GET /v1/usage`. No `Retry-After` — credits reset at the billing-period boundary."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_CREDITS
                  type: payment_required
                  message: This operation required more credits than the 0 remaining on the 'free' plan. See the per-operation cost in GET /v1/help.
                  suggestion: Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.
                  docs: https://docs.brew.new/api-reference/api/credits
                  details:
                    cost: 2
                    remaining: 0
                    planKey: free
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: The source image/video could not be processed (unreachable URL, non-decodable media, or upload failure).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a25
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
        "503":
          description: The credit balance could not be verified (a transient billing dependency outage). The gate fails closed rather than do paid work it cannot meter. Retryable — `Retry-After` indicates when.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: SERVICE_UNAVAILABLE
                  type: service_unavailable
                  message: Your credit balance could not be verified because a billing dependency is temporarily unavailable.
                  suggestion: Retry the request after a short delay.
                  docs: https://docs.brew.new/api-reference/api/credits
                  retryAfter: 2
  /v1/content/add-image:
    post:
      operationId: contentAddImage
      tags:
        - Content
      summary: Add image
      description: "Adds image URLs to the brand image library: fetches them, optimizes them, stores them, and vector-indexes them so the email agent can find them. Pass `imageUrl` for one synchronous import or `imageUrls` for up to 100 images in a durable background import. Free; no credits are charged."
      parameters:
        - *a1
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      requestBody:
        required: true
        description: Pass one public `imageUrl` for a synchronous import, or `imageUrls` with 1–100 public URLs for a durable batch import.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContentAddImageRequest"
      responses:
        "200":
          description: The image was optimized, saved to the brand library, and rehosted; `url` is a durable cdn.brew.new URL.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContentAddImageResponse"
              example:
                url: https://cdn.brew.new/api-host-3f2c8d9a-1b4e-4c7a-9e21-7d6f0a5b1c34.png
                width: 1200
                height: 675
                aspectRatio: wide
        "202":
          description: The batch was accepted for durable import; images appear in the brand library progressively.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContentAddImageBatchResponse"
              example:
                accepted: 3
                skipped: 1
                runId: brand-image-import-01JZ9X8Y7W6V5T4S3R2Q1P0N9M
        "400":
          description: "The request body or query string was invalid (unknown key, wrong type, or missing required field). Strict schemas reject unknown keys — including `brandId`: a brand is named with the `X-Brand-Id` HEADER (organization-scoped credentials) or resolved from the credential itself (brand-scoped ones), never as a body or query field."
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_REQUEST
                  type: invalid_request
                  message: Request validation failed.
                  suggestion: Fix the field reported in `param` and retry.
                  docs: https://docs.brew.new/api-reference/api/errors
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "409":
          description: The same `Idempotency-Key` was reused with a different request body.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: IDEMPOTENCY_CONFLICT
                  type: conflict
                  message: The same idempotency key was reused with a different request payload.
                  suggestion: Reuse the original payload or send a new idempotency key.
                  docs: https://docs.brew.new/api-reference/api/idempotency
        "422":
          description: The source image/video could not be processed (unreachable URL, non-decodable media, or upload failure).
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example: *a25
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/usage:
    get:
      operationId: getUsage
      tags:
        - Usage
      summary: Get usage
      description: "Returns the org usage snapshot: current plan, AI credit balance (limit/used/remaining — `null` = unlimited), monthly email-send quota, and the billing-period window. Check it before a credit-metered call."
      responses:
        "200":
          description: Usage snapshot — plan, credits, and email-send quota.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageGetResponse"
              example:
                plan:
                  key: pro
                  name: Pro
                credits:
                  limit: 50000
                  used: 364
                  remaining: 49636
                emailSends:
                  limit: 200000
                  used: 0
                  remaining: 200000
                period:
                  start: 2026-05-28T18:10:35.000Z
                  end: 2026-06-28T18:10:35.000Z
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/integrations:
    get:
      operationId: listIntegrations
      tags:
        - Integrations
      summary: List integrations
      description: Returns the product integration catalog for the brand in scope, with a `connected` flag per provider. Connecting is a human Settings hop at `/integrations/{provider}` — never paste a connect URL into model output. Brand-scoped (`X-Brand-Id` on an org credential). No permission scope.
      responses:
        "200":
          description: Catalog rows for every known provider.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntegrationsListResponse"
              example:
                data:
                  - provider: klaviyo
                    name: Klaviyo
                    category: data_out
                    connected: true
                  - provider: slack
                    name: Slack
                    category: data_in
                    connected: false
                    comingSoon: true
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
      parameters:
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
  /v1/api-keys:
    get:
      operationId: listApiKeys
      tags:
        - API Keys
      summary: List API keys
      description: Lists API keys in the organization. A brand-scoped credential only sees keys bound to its brand. Organization-level — takes no `X-Brand-Id`. `brandId` on a row is the key's binding, not the request actor. No permission scope.
      responses:
        "200":
          description: API keys this credential may see.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeysListResponse"
              example:
                data:
                  - keyId: kd7b3s7fapqz8mjm12ekz1kxdx87yceg
                    name: CI
                    keyPreview: brew_abc...wxyz
                    createdAt: 2026-04-08T12:00:00.000Z
                    status: active
                    permissions:
                      - all
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
    post:
      operationId: createApiKey
      tags:
        - API Keys
      summary: Create an API key
      description: Mints a new API key. The plaintext `key` is returned once. `brandId` in the body is the NEW KEY's binding (omit for an organization-wide key) — the only v1 body field named `brandId`. Permissions default to `["all"]` and cannot exceed the caller's grant. Organization-wide keys require an org-admin dashboard session or an organization-scoped credential.
      parameters:
        - *a1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ApiKeysCreateRequest"
            example:
              name: CI
              permissions:
                - emails
                - domains
              brandId: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "201":
          description: The new key. Store `key` now — it is not shown again.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeysCreateResponse"
              example:
                key: brew_abcdefghijklmnopqrstuvwxyz012345
                keyId: kd7b3s7fapqz8mjm12ekz1kxdx87yceg
                message: Save this key securely. You won't be able to see it again.
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/api-keys/{keyId}:
    delete:
      operationId: revokeApiKey
      tags:
        - API Keys
      summary: Revoke an API key
      description: Revokes an API key. Organization-wide keys require an org-admin dashboard session or an organization-scoped credential. A brand credential cannot see or revoke another brand's keys (`404`).
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: API key id returned by `GET /v1/api-keys` or `POST /v1/api-keys`.
            example: kd7b3s7fapqz8mjm12ekz1kxdx87yceg
          required: true
          description: API key id returned by `GET /v1/api-keys` or `POST /v1/api-keys`.
          name: keyId
          in: path
      responses:
        "200":
          description: The key was revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeysDeleteResponse"
              example:
                keyId: kd7b3s7fapqz8mjm12ekz1kxdx87yceg
                revoked: true
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
  /v1/health:
    get:
      operationId: getHealth
      tags:
        - Health
      summary: Liveness probe
      description: 'No auth, no rate limit — a public liveness surface a dependent service (e.g. the Brew MCP server) can poll. Returns `{ status: "ok", version }`.'
      security: []
      responses:
        "200":
          description: The service is up.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: false
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthResponse"
              example:
                status: ok
                version: v1
  /v1/help:
    get:
      operationId: getHelp
      tags:
        - Meta
      summary: Machine-readable API catalog
      description: "No auth, no rate limit — a structured-JSON catalog an MCP server (or any agent) can parse to self-discover how to use Brew: auth, permission scopes, rate limits, flat credit costs, the error envelope, and the full endpoint list (derived from this same OpenAPI document, so it never drifts). Returns a generic JSON object; read the live response for the concrete shape."
      security: []
      responses:
        "200":
          description: The API catalog.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: false
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HelpResponse"
  /v1/chats/{chatId}:
    get:
      operationId: getChatContext
      tags:
        - Chats
      summary: Get chat context
      description: "Read a brand-scoped digest of a Brew chat for resuming the conversation in an external agent: the emails + automations it created/referenced (latest version, with preview), the trigger events it touched, and a trimmed tail of the transcript. Read-only and free. `404 CHAT_NOT_FOUND` for an unknown id OR a chat owned by a different brand (the two are indistinguishable)."
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
            description: The Brew chat id (from the chat URL / the app).
            example: Hk2mZ8t9QbY3sW1vR0pLd
          required: true
          description: The Brew chat id (from the chat URL / the app).
          name: chatId
          in: path
        - name: X-Brand-Id
          in: header
          required: false
          description: The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: kx7b3s7fapqz8mjm12ekz1kxdx87yceg
      responses:
        "200":
          description: The chat context digest.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
          content:
            application/json:
              schema:
                type: object
                properties:
                  chatId:
                    type: string
                  title:
                    type:
                      - string
                      - "null"
                  modelId:
                    type:
                      - string
                      - "null"
                  updatedAt:
                    type:
                      - string
                      - "null"
                  messageCount:
                    type: number
                  artifacts:
                    type: array
                    items:
                      type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - email
                            - automation
                        id:
                          type: string
                        title:
                          type: string
                        imageUrl:
                          type: string
                      required:
                        - type
                        - id
                        - title
                  triggerEventIds:
                    type: array
                    items:
                      type: string
                  recentMessages:
                    type: array
                    items:
                      type: object
                      properties:
                        role:
                          type: string
                          enum:
                            - user
                            - assistant
                            - system
                        text:
                          type: string
                      required:
                        - role
                        - text
                required:
                  - chatId
                  - title
                  - modelId
                  - updatedAt
                  - messageCount
                  - artifacts
                  - triggerEventIds
                  - recentMessages
              example:
                chatId: Hk2mZ8t9QbY3sW1vR0pLd
                title: Spring launch campaign
                modelId: anthropic/claude-opus-5
                updatedAt: 2026-06-30T12:34:56.789Z
                messageCount: 18
                artifacts:
                  - type: email
                    id: tCYL9yyvZZ5XmR6saDR-M
                    title: Spring Launch — Hero
                    imageUrl: https://cdn.brew.new/email-preview-tCYL9yyvZZ5XmR6saDR-M.png
                  - type: automation
                    id: au_7t2
                    title: Welcome series
                triggerEventIds:
                  - te_signup
                recentMessages:
                  - role: user
                    text: Make the hero bolder and add a CTA.
                  - role: assistant
                    text: Updated the hero and added a "Shop now" button.
        "401":
          description: The API key was missing, invalid, or revoked.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INVALID_API_KEY
                  type: authentication_error
                  message: The provided API key is invalid.
                  suggestion: Check the API key format and retry with a valid active key.
                  docs: https://docs.brew.new/api-reference/api/authentication
        "403":
          description: The caller does not have the required `emails` permission.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  type: authorization_error
                  message: The caller does not have the required permission.
                  suggestion: Use an API key or session with the required permission.
                  docs: https://docs.brew.new/api-reference/api/authentication
                  param: emails
        "404":
          description: Chat not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: CHAT_NOT_FOUND
                  type: not_found
                  message: The requested chat 'chat_xxx' was not found.
                  suggestion: Check the chatId, and that your key/connector is bound to that chat’s brand.
                  docs: https://docs.brew.new/api-reference/api/errors
                  param: chatId
        "429":
          description: The request hit the rolling rate limit window.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
            X-RateLimit-Limit:
              schema:
                type: integer
                description: Requests allowed in the current rolling rate limit window.
                example: 100
              required: true
              description: Requests allowed in the current rolling rate limit window.
            X-RateLimit-Remaining:
              schema:
                type: integer
                description: Requests remaining in the current rolling rate limit window.
                example: 99
              required: true
              description: Requests remaining in the current rolling rate limit window.
            X-RateLimit-Reset:
              schema:
                type: integer
                description: Unix timestamp in seconds for when the rolling window fully resets.
                example: 1712592360
              required: true
              description: Unix timestamp in seconds for when the rolling window fully resets.
            Retry-After:
              schema:
                type: integer
                description: Seconds to wait before retrying the request.
                example: 42
              required: true
              description: Seconds to wait before retrying the request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: RATE_LIMITED
                  type: rate_limit
                  message: Too many requests.
                  suggestion: Wait for the retry window before sending another request.
                  docs: https://docs.brew.new/api-reference/api/rate-limits
                  retryAfter: 42
        "500":
          description: Unexpected internal error.
          headers:
            x-request-id:
              schema:
                type: string
                description: Unique request identifier. Share this with support when debugging a request.
                example: req_8cac13fd94e6420cacdd75a1aa403a28
              required: true
              description: Unique request identifier. Share this with support when debugging a request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorEnvelope"
              example:
                error:
                  code: INTERNAL_ERROR
                  type: internal_error
                  message: An unexpected error occurred.
                  suggestion: Retry the request. If it keeps failing, contact support.
                  docs: https://docs.brew.new/api-reference/api/errors
webhooks: {}
