{
  "openapi": "3.1.0",
  "info": {
    "title": "Rykon Mail API",
    "version": "1.0.0",
    "summary": "Transactional email, your audience, campaigns, domains, mailboxes and AI agents.",
    "description": "Every request is authenticated with an API key sent as Authorization: Bearer rmk_live_.... Each operation names the scope its key must hold in x-scope. Errors are JSON: {\"error\": \"<code>\", \"message\": \"<sentence>\"}. Guides: https://rykonmail.com/docs",
    "contact": {
      "name": "Rykon Mail",
      "url": "https://rykonmail.com/docs"
    }
  },
  "servers": [
    {
      "url": "https://app.rykonmail.com/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Emails",
      "description": "Send transactional email from your application: receipts, password resets, alerts."
    },
    {
      "name": "Contacts",
      "description": "The people in your audience, with their consent and the topics they chose."
    },
    {
      "name": "Topics",
      "description": "What people can subscribe to, so each one hears only about what they asked for."
    },
    {
      "name": "Forms",
      "description": "Sign-up forms and where they are live."
    },
    {
      "name": "Campaigns",
      "description": "Create, test, schedule and measure campaigns."
    },
    {
      "name": "Automations",
      "description": "Journeys that run when someone subscribes."
    },
    {
      "name": "Domains",
      "description": "Your sending domains and the DNS records that prove them."
    },
    {
      "name": "Mailboxes",
      "description": "Mailboxes on your domains."
    },
    {
      "name": "Aliases",
      "description": "Extra addresses that deliver to a mailbox."
    },
    {
      "name": "AI agents",
      "description": "Agents with mailboxes of their own, and the messages waiting for your approval."
    }
  ],
  "paths": {
    "/emails": {
      "post": {
        "operationId": "emails.send",
        "summary": "Send an email",
        "description": "Sends one transactional email: a message your application sends one person because of something they did, such as a receipt, a sign-in link or an order update. It carries no unsubscribe link, so the rules are strict. An address that bounced or marked your mail as spam is never sent to. Someone who unsubscribed may still get account, security, receipt and order mail, but never a notification, and never a message that reads as selling; that is refused with the words that gave it away. Refusals answer 409 and are listed in GET /emails. The from address must be on one of your domains that is set up for sending (400 if the domain is not yours, 409 if it is not ready, 409 if sending is stopped for the account). One address gets at most 20 messages a day, and the account has an hourly limit by plan; either answers 429. Give text, html or both; without text, a plain text part is made from the HTML. Send an idempotencyKey to make retries safe: the same key returns the first message with \"repeated\": true instead of sending again. The message body is not kept, only who, when, the subject and the outcome. Needs a key holding mail:send.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mail:send",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "from": {
                    "type": "string",
                    "format": "email",
                    "description": "The sender. Its domain must be one of yours, verified and set up for sending."
                  },
                  "fromName": {
                    "type": "string",
                    "description": "A display name for the sender, up to 120 characters."
                  },
                  "to": {
                    "type": "string",
                    "format": "email",
                    "description": "The one recipient."
                  },
                  "replyTo": {
                    "type": "string",
                    "format": "email",
                    "description": "Where replies go."
                  },
                  "subject": {
                    "type": "string",
                    "description": "1 to 300 characters."
                  },
                  "text": {
                    "type": "string",
                    "description": "The plain text part, up to 200,000 characters. Give text, html or both."
                  },
                  "html": {
                    "type": "string",
                    "description": "The HTML part, up to 500,000 characters."
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "account",
                      "security",
                      "receipt",
                      "order",
                      "notification"
                    ],
                    "description": "What kind of message this is. Only account, security, receipt and order mail may reach someone who unsubscribed."
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "description": "Up to 200 characters. A retry with the same key returns the first message and sends nothing."
                  }
                },
                "required": [
                  "from",
                  "to",
                  "subject",
                  "category"
                ]
              },
              "example": {
                "from": "orders@northwind-local.test",
                "fromName": "Northwind Traders",
                "to": "jamie.chen@example.com",
                "replyTo": "help@northwind-local.test",
                "subject": "Your receipt for order 10482",
                "text": "Thanks for your order.\n\nOrder 10482: 2 x Linen apron, $48.00.\nTotal paid: $48.00.",
                "html": "<p>Thanks for your order.</p><p>Order 10482: 2 x Linen apron, $48.00.<br>Total paid: <strong>$48.00</strong>.</p>",
                "category": "receipt",
                "idempotencyKey": "order-10482-receipt"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "682e5ffd-1528-4b9e-9b81-65903d3d9593",
                  "category": "receipt",
                  "from": "orders@northwind-local.test",
                  "to": "jamie.chen@example.com",
                  "subject": "Your receipt for order 10482",
                  "state": "sent",
                  "messageId": "simulated-fa61a1bd-2389-4b00-ab0c-63ac54867b0c",
                  "error": null,
                  "createdAt": "2026-10-30T06:18:05.177Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "get": {
        "operationId": "emails.list",
        "summary": "List sent emails",
        "description": "The 100 most recent transactional messages, newest first, including the ones that were refused and why. With them: how many were sent in the last hour and day, how many were refused today, the account's hourly limit and the most one address may get in a day. Bodies are never kept, so they are not here. Needs sending:read.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "sending:read",
        "parameters": [
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Only messages to this address.",
            "schema": {
              "type": "string",
              "format": "email"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Only messages in this state.",
            "schema": {
              "type": "string",
              "enum": [
                "sent",
                "refused",
                "failed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "messages": [
                    {
                      "id": "ba525624-1079-436d-9525-88eb1b013547",
                      "category": "order",
                      "from": "orders@northwind-local.test",
                      "to": "jamie.chen@example.com",
                      "subject": "20% off everything this weekend",
                      "state": "refused",
                      "messageId": null,
                      "error": "jamie.chen@example.com unsubscribed and this reads as marketing (% off, shop now); transactional mail must not sell",
                      "createdAt": "2026-10-30T06:18:05.232Z"
                    },
                    {
                      "id": "682e5ffd-1528-4b9e-9b81-65903d3d9593",
                      "category": "receipt",
                      "from": "orders@northwind-local.test",
                      "to": "jamie.chen@example.com",
                      "subject": "Your receipt for order 10482",
                      "state": "sent",
                      "messageId": "simulated-fa61a1bd-2389-4b00-ab0c-63ac54867b0c",
                      "error": null,
                      "createdAt": "2026-10-30T06:18:05.177Z"
                    }
                  ],
                  "lastHour": 1,
                  "lastDay": 27,
                  "refusedToday": 25,
                  "hourlyLimit": 2000,
                  "perRecipientPerDay": 20
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/contacts": {
      "get": {
        "operationId": "contacts.list",
        "summary": "List contacts",
        "description": "Contacts, newest first, with the account's totals by status (the totals count everyone, not just this page). Needs audience:read.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only contacts with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "subscribed",
                "unsubscribed",
                "bounced",
                "complained"
              ]
            }
          },
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "description": "Only contacts with this tag.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Part of an email address or a name; case does not matter.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1 to 500; 100 if left out.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "How many to skip, for the next page; 0 if left out.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "contacts": [
                    {
                      "id": "00410db1-2799-4dd4-afef-11f95befa5af",
                      "email": "jamie.chen@example.com",
                      "name": "Jamie Chen",
                      "status": "subscribed",
                      "tags": [
                        "customer",
                        "vip"
                      ],
                      "consent_source": "api:Checkout opt-in",
                      "consent_at": "2026-10-30T06:13:46.762Z",
                      "confirmed_at": "2026-10-30T06:13:46.762Z",
                      "unsubscribed_at": null,
                      "created_at": "2026-10-30T06:13:46.762Z"
                    }
                  ],
                  "totals": {
                    "subscribed": 3,
                    "pending": 7,
                    "unsubscribed": 1
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "post": {
        "operationId": "contacts.create",
        "summary": "Add a contact",
        "description": "Adds someone to your audience, with the consent they gave recorded word for word: what they agreed to, where, and optionally from which IP address. Answers 201 for a new contact. If the address is already subscribed (or pending, when you ask for double opt-in again), the contact is filled in rather than replaced: a name if given, new tags and attributes merged in, nothing taken away; that answers 200 with \"created\": false. With doubleOptIn the person is sent a confirmation email and stays pending until they use its link, which expires in 7 days; without it they are subscribed at once and any automation that starts on subscribing starts. Two things only the person can do: an address that unsubscribed or asked to be erased comes back only through their own confirmation, so it answers 409 unless doubleOptIn is true; and an address that bounced or marked your mail as spam can never be added again (409). Needs audience:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Up to 320 characters; stored in lower case."
                  },
                  "name": {
                    "type": "string",
                    "description": "Up to 200 characters."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 20 tags of up to 40 characters each."
                  },
                  "attributes": {
                    "type": "object",
                    "description": "Up to 50 fields of your own: keys up to 60 characters, values a string (up to 500), number, boolean or null."
                  },
                  "consent": {
                    "type": "object",
                    "description": "What the person agreed to: text (10 to 2,000 characters, in the words they saw, required), source (where they agreed, up to 120 characters; \"API\" if left out) and ip (optional)."
                  },
                  "doubleOptIn": {
                    "type": "boolean",
                    "description": "Send a confirmation email and keep the contact pending until it is used. false if left out."
                  }
                },
                "required": [
                  "email",
                  "consent"
                ]
              },
              "example": {
                "email": "jamie.chen@example.com",
                "name": "Jamie Chen",
                "tags": [
                  "customer",
                  "newsletter"
                ],
                "attributes": {
                  "plan": "pro",
                  "city": "Austin"
                },
                "consent": {
                  "text": "Yes, send me product news and offers. I can unsubscribe at any time.",
                  "source": "Checkout opt-in",
                  "ip": "203.0.113.24"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "00410db1-2799-4dd4-afef-11f95befa5af",
                  "email": "jamie.chen@example.com",
                  "name": "Jamie Chen",
                  "status": "subscribed",
                  "tags": [
                    "customer",
                    "newsletter"
                  ],
                  "attributes": {
                    "city": "Austin",
                    "plan": "pro"
                  },
                  "consent_source": "api:Checkout opt-in",
                  "consent_at": "2026-10-30T06:13:46.762Z",
                  "confirmed_at": "2026-10-30T06:13:46.762Z",
                  "unsubscribed_at": null,
                  "created_at": "2026-10-30T06:13:46.762Z",
                  "created": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/contacts/import/preview": {
      "post": {
        "operationId": "contacts.import_preview",
        "summary": "Preview a CSV import",
        "description": "Reads a CSV file without importing anything: its columns, what each would become (guessed when you send no mapping), the first rows, and how many people are new, already on the list, or suppressed and so would be skipped, with the first 50 invalid addresses and duplicates. The file can be up to 5 MB and 50,000 rows. A mapping entry is email, name, first_name, last_name, tags, ignore, or field:<key> for a field of your own. Needs audience:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "csv": {
                    "type": "string",
                    "description": "The file's contents, with a header row."
                  },
                  "mapping": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "What each column holds, one entry per column. Guessed from the headers if left out."
                  }
                },
                "required": [
                  "csv"
                ]
              },
              "example": {
                "csv": "email,first_name,last_name,company\nava.patel@example.com,Ava,Patel,Acme\nnoah.kim@example.com,Noah,Kim,Globex\nnot-an-address,Bad,Row,\nava.patel@example.com,Ava,Patel,Acme\n"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "headers": [
                    "email",
                    "first_name"
                  ],
                  "mapping": [
                    "email",
                    "first_name"
                  ],
                  "sample": [
                    [
                      "ava.patel@example.com",
                      "Ava"
                    ],
                    [
                      "noah.kim@example.com",
                      "Noah"
                    ]
                  ],
                  "total": 4,
                  "valid": 2,
                  "new": 2,
                  "existing": 0,
                  "suppressed": 0,
                  "invalid": [
                    {
                      "line": 4,
                      "value": "not-an-address"
                    }
                  ],
                  "invalidCount": 1,
                  "duplicates": [
                    {
                      "line": 5,
                      "email": "ava.patel@example.com"
                    }
                  ],
                  "duplicateCount": 1,
                  "needsEmailColumn": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/contacts/import": {
      "post": {
        "operationId": "contacts.import",
        "summary": "Import contacts from CSV",
        "description": "Imports a CSV file. An upload is never consent, so you declare where these people came from: basis \"subscribed\" is your own statement that they agreed, recorded word for word on every contact created; \"unconfirmed\" keeps them pending, and pending contacts are never sent marketing. People already on the list keep their status: an import only adds tags and fills empty fields. Unsubscribed, bounced and complained addresses are skipped. The mapping must have one entry per column and exactly one email column. Every import can be undone. Same limits as the preview. Needs audience:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "csv": {
                    "type": "string",
                    "description": "The file's contents, with a header row."
                  },
                  "mapping": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "What each column holds: email, name, first_name, last_name, tags, ignore or field:<key>."
                  },
                  "basis": {
                    "type": "string",
                    "enum": [
                      "subscribed",
                      "unconfirmed"
                    ],
                    "description": "Whether these people agreed to hear from you, by your declaration, or still need to confirm."
                  },
                  "consentText": {
                    "type": "string",
                    "description": "20 to 1,000 characters: where these people came from and how they agreed."
                  },
                  "declaration": {
                    "type": "boolean",
                    "description": "Must be true: you confirm the declaration above."
                  },
                  "fileName": {
                    "type": "string",
                    "description": "The file's name, for the import's record."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 10 tags to add to everyone in the file: lower case letters, numbers and dashes."
                  }
                },
                "required": [
                  "csv",
                  "mapping",
                  "basis",
                  "consentText",
                  "declaration"
                ]
              },
              "example": {
                "csv": "email,first_name,last_name,company\nava.patel@example.com,Ava,Patel,Acme\nnoah.kim@example.com,Noah,Kim,Globex\nnot-an-address,Bad,Row,\nava.patel@example.com,Ava,Patel,Acme\n",
                "fileName": "webinar-signups.csv",
                "mapping": [
                  "email",
                  "first_name",
                  "last_name",
                  "field:company"
                ],
                "basis": "unconfirmed",
                "consentText": "People who registered for our October webinar and ticked the box to hear from us.",
                "declaration": true,
                "tags": [
                  "webinar"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "7ba4f9fa-30c1-4d1a-807e-0d8c3f057d6b",
                  "rows": 4,
                  "created": 2,
                  "updated": 0,
                  "skippedInvalid": 1,
                  "skippedDuplicate": 1,
                  "skippedSuppressed": 0,
                  "basis": "unconfirmed"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/contacts/imports": {
      "get": {
        "operationId": "contacts.imports",
        "summary": "List imports",
        "description": "The 50 most recent imports, newest first, with their counts, their declaration and whether they were undone. Needs audience:read.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "imports": [
                    {
                      "id": "7ba4f9fa-30c1-4d1a-807e-0d8c3f057d6b",
                      "file_name": "webinar-signups.csv",
                      "basis": "unconfirmed",
                      "consent_text": "People who registered for our October webinar and ticked the box to hear from us.",
                      "tags": [
                        "webinar"
                      ],
                      "rows": 4,
                      "created": 2,
                      "updated": 0,
                      "skipped_invalid": 1,
                      "skipped_duplicate": 1,
                      "skipped_suppressed": 0,
                      "created_by": "key sa1pteyz44qbm",
                      "created_at": "2026-10-30T06:13:57.624Z",
                      "undone_at": null,
                      "undone_by": null,
                      "undo_kept": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/contacts/imports/{id}/undo": {
      "post": {
        "operationId": "contacts.import_undo",
        "summary": "Undo an import",
        "description": "Removes the people an import created who have not been sent anything since and have not signed up again by themselves, and takes off the tags it added to people who were already there. \"kept\" counts the people it created who stay. An import is undone once; a second try answers 409. Needs audience:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The import's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "removed": 2,
                  "kept": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/contacts/{id}": {
      "get": {
        "operationId": "contacts.get",
        "summary": "Get a contact",
        "description": "One contact, with the consent on record (its text, source, time and IP address) and its 100 most recent events. Needs audience:read.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "00410db1-2799-4dd4-afef-11f95befa5af",
                  "email": "jamie.chen@example.com",
                  "name": "Jamie Chen",
                  "status": "subscribed",
                  "tags": [
                    "customer",
                    "vip"
                  ],
                  "attributes": {
                    "plan": "business"
                  },
                  "consent_source": "api:Checkout opt-in",
                  "consent_text": "Yes, send me product news and offers. I can unsubscribe at any time.",
                  "consent_at": "2026-10-30T06:13:46.762Z",
                  "consent_ip": "203.0.113.24",
                  "confirmed_at": "2026-10-30T06:13:46.762Z",
                  "unsubscribed_at": null,
                  "created_at": "2026-10-30T06:13:46.762Z",
                  "events": [
                    {
                      "kind": "updated",
                      "detail": {
                        "by": "key sa1pteyz44qbm",
                        "via": "api"
                      },
                      "created_at": "2026-10-30T06:13:46.890Z"
                    },
                    {
                      "kind": "updated",
                      "detail": {
                        "by": "key sa1pteyz44qbm",
                        "via": "api"
                      },
                      "created_at": "2026-10-30T06:13:46.833Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "patch": {
        "operationId": "contacts.update",
        "summary": "Update a contact",
        "description": "Changes a contact's name, tags and attributes. It never changes status: only the person's consent and unsubscribing do that. Attributes are merged in, and an attribute set to null is removed. Fields other than these are refused with 400. Needs audience:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Up to 200 characters; null clears it."
                  },
                  "addTags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 20 tags to add."
                  },
                  "removeTags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 20 tags to remove."
                  },
                  "attributes": {
                    "type": "object",
                    "description": "Fields to set: a string (up to 500), number or boolean; null removes the field."
                  }
                }
              },
              "example": {
                "name": "Jamie Chen",
                "addTags": [
                  "vip"
                ],
                "removeTags": [
                  "newsletter"
                ],
                "attributes": {
                  "plan": "business",
                  "city": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "00410db1-2799-4dd4-afef-11f95befa5af",
                  "email": "jamie.chen@example.com",
                  "name": "Jamie Chen",
                  "status": "subscribed",
                  "tags": [
                    "customer",
                    "vip"
                  ],
                  "attributes": {
                    "plan": "business"
                  },
                  "consent_source": "api:Checkout opt-in",
                  "consent_at": "2026-10-30T06:13:46.762Z",
                  "confirmed_at": "2026-10-30T06:13:46.762Z",
                  "unsubscribed_at": null,
                  "created_at": "2026-10-30T06:13:46.762Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "delete": {
        "operationId": "contacts.delete",
        "summary": "Erase a contact",
        "description": "Erasure, for a request to be forgotten: the contact and their history are deleted. Their address stays on your suppression list so they are never mailed again by mistake; adding them back takes their own confirmation (POST /contacts with doubleOptIn). Needs audience:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "erased": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/contacts/{id}/unsubscribe": {
      "post": {
        "operationId": "contacts.unsubscribe",
        "summary": "Unsubscribe a contact",
        "description": "Unsubscribes someone on their behalf, for example when they ask you by email. They are added to your suppression list and taken out of any automation they are in. Only their own confirmation can bring them back. Needs audience:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "00410db1-2799-4dd4-afef-11f95befa5af",
                  "status": "unsubscribed"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/contacts/{id}/topics": {
      "get": {
        "operationId": "contacts.topics",
        "summary": "List a contact's topics",
        "description": "Every topic on the account, with when this person opted out of it and how, or null if they still receive it. Needs audience:read.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "topics": [
                    {
                      "id": "4d3e3999-dcc6-4f7f-898c-e7ab1e971c3e",
                      "name": "Offers 88153",
                      "opted_out_at": null,
                      "source": null
                    },
                    {
                      "id": "ffbf4d82-d5fe-401a-b7c1-aea54f759542",
                      "name": "Offers 76520",
                      "opted_out_at": null,
                      "source": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/contacts/{id}/topics/{topicId}": {
      "put": {
        "operationId": "contacts.set_topic",
        "summary": "Set a contact's topic choice",
        "description": "Records a choice the person made about one topic: whether they receive it. Use it only on their request; the contact's history keeps who recorded it. Unsubscribing still stops everything; a topic only narrows. Needs audience:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "topicId",
            "in": "path",
            "required": true,
            "description": "The topic's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "receives": {
                    "type": "boolean",
                    "description": "true to receive the topic again, false to opt out of it."
                  }
                },
                "required": [
                  "receives"
                ]
              },
              "example": {
                "receives": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "receives": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/topics": {
      "get": {
        "operationId": "topics.list",
        "summary": "List topics",
        "description": "The account's topics, oldest first, with how many people opted out of each and how many campaigns use it. Needs audience:read.",
        "tags": [
          "Topics"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "topics": [
                    {
                      "id": "bea753b0-6132-4bc2-bc2a-18ff86ed0079",
                      "name": "Product updates",
                      "description": "New features and fixes, about once a month.",
                      "created_at": "2026-10-30T06:13:45.895Z",
                      "opted_out": 0,
                      "campaigns": 0
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "post": {
        "operationId": "topics.create",
        "summary": "Create a topic",
        "description": "Adds a kind of email people can opt out of on its own, such as product updates or offers. Everyone subscribed receives a topic until they opt out of it; a campaign that names a topic leaves out those who did. Names are unique on the account (400 if taken), and an account can have 30 topics (400 beyond that). Needs audience:write.",
        "tags": [
          "Topics"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1 to 60 characters."
                  },
                  "description": {
                    "type": "string",
                    "description": "Up to 200 characters, shown to people choosing what they receive."
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "Product updates",
                "description": "New features and changes, about once a month."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "bea753b0-6132-4bc2-bc2a-18ff86ed0079",
                  "name": "Product updates",
                  "description": "New features and changes, about once a month.",
                  "created_at": "2026-10-30T06:13:45.895Z",
                  "opted_out": 0,
                  "campaigns": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/topics/{id}": {
      "patch": {
        "operationId": "topics.update",
        "summary": "Update a topic",
        "description": "Renames a topic or changes its description; send only what changes. A name already used answers 400. Needs audience:write.",
        "tags": [
          "Topics"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The topic's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1 to 60 characters."
                  },
                  "description": {
                    "type": "string",
                    "description": "Up to 200 characters."
                  }
                }
              },
              "example": {
                "description": "New features and fixes, about once a month."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "bea753b0-6132-4bc2-bc2a-18ff86ed0079",
                  "name": "Product updates",
                  "description": "New features and fixes, about once a month.",
                  "created_at": "2026-10-30T06:13:45.895Z",
                  "opted_out": 0,
                  "campaigns": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "delete": {
        "operationId": "topics.delete",
        "summary": "Archive a topic",
        "description": "Archives a topic. It is never deleted, because past campaigns and people's choices still point at it; draft campaigns that named it no longer do. Needs audience:write.",
        "tags": [
          "Topics"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The topic's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "archived": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/forms": {
      "get": {
        "operationId": "forms.list",
        "summary": "List forms",
        "description": "The account's sign-up forms, newest first, with how many contacts joined through each and the five sites it was most recently seen on. siteOrigin is where hosted forms live (/f/<public_id>). Needs audience:read.",
        "tags": [
          "Forms"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "forms": [
                    {
                      "id": "a5f0dd2d-bfc1-4247-84fa-6a8ff0dd0740",
                      "public_id": "9QAqDsJMl79DfFKY",
                      "name": "API docs example",
                      "heading": "Get our monthly letter",
                      "description": "New products and studio notes, about once a month.",
                      "button_label": "Sign me up",
                      "consent_text": "I agree to receive emails from us. I can unsubscribe at any time with the link in every email.",
                      "ask_name": true,
                      "double_opt_in": true,
                      "success_message": "Thanks. Check your inbox to confirm.",
                      "redirect_url": null,
                      "reply_to": null,
                      "tags": [
                        "newsletter"
                      ],
                      "active": false,
                      "allowed_sites": [
                        "example.com"
                      ],
                      "created_at": "2026-10-30T06:14:07.200Z",
                      "updated_at": "2026-10-30T06:14:07.475Z",
                      "contacts": 0,
                      "placements": []
                    }
                  ],
                  "siteOrigin": "http://localhost:4320"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "post": {
        "operationId": "forms.create",
        "summary": "Create a form",
        "description": "Makes a sign-up form. People who submit it become contacts with the form's consent text recorded; with double opt-in (the default) they are subscribed only once they confirm. Creating a live form beyond your plan's live form limit answers 402; create it with active false, or switch another off. Needs audience:write.",
        "tags": [
          "Forms"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Your name for the form, 1 to 120 characters."
                  },
                  "heading": {
                    "type": "string",
                    "description": "Up to 160 characters; \"Stay in touch\" if left out."
                  },
                  "description": {
                    "type": "string",
                    "description": "Up to 600 characters."
                  },
                  "buttonLabel": {
                    "type": "string",
                    "description": "Up to 40 characters; \"Subscribe\" if left out."
                  },
                  "consentText": {
                    "type": "string",
                    "description": "What the person agrees to, 10 to 1,000 characters, recorded word for word on every contact. A sensible default if left out."
                  },
                  "askName": {
                    "type": "boolean",
                    "description": "Ask for a name as well as an address. true if left out."
                  },
                  "doubleOptIn": {
                    "type": "boolean",
                    "description": "Subscribe people only once they use the link mailed to them. true if left out."
                  },
                  "successMessage": {
                    "type": "string",
                    "description": "Shown after submitting, up to 300 characters."
                  },
                  "redirectUrl": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uri",
                    "description": "A page to send people to after submitting, instead of the message."
                  },
                  "replyTo": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "email",
                    "description": "Where replies to the confirmation email go."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 10 tags given to everyone who signs up: lower case letters, numbers and dashes."
                  },
                  "active": {
                    "type": "boolean",
                    "description": "Whether the form takes sign-ups. true if left out."
                  },
                  "allowedSites": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 20 host names the form may be shown on, like yourcompany.com; empty for anywhere. \"www.\" is dropped."
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "API docs example",
                "heading": "Get our monthly letter",
                "description": "New products and studio notes, about once a month.",
                "tags": [
                  "newsletter"
                ],
                "allowedSites": [
                  "example.com"
                ],
                "active": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "a5f0dd2d-bfc1-4247-84fa-6a8ff0dd0740",
                  "public_id": "9QAqDsJMl79DfFKY",
                  "name": "API docs example",
                  "heading": "Get our monthly letter",
                  "description": "New products and studio notes, about once a month.",
                  "button_label": "Subscribe",
                  "consent_text": "I agree to receive emails from us. I can unsubscribe at any time with the link in every email.",
                  "ask_name": true,
                  "double_opt_in": true,
                  "success_message": "Thanks. Check your inbox to confirm.",
                  "redirect_url": null,
                  "reply_to": null,
                  "tags": [
                    "newsletter"
                  ],
                  "active": false,
                  "allowed_sites": [
                    "example.com"
                  ],
                  "created_at": "2026-10-30T06:14:07.200Z",
                  "updated_at": "2026-10-30T06:14:07.200Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/forms/{id}": {
      "patch": {
        "operationId": "forms.update",
        "summary": "Update a form",
        "description": "Changes a form; send only what changes. Switching a form on counts against your plan's live form limit and answers 402 when there is no room; editing or switching off never does. Needs audience:write.",
        "tags": [
          "Forms"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The form's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Your name for the form, 1 to 120 characters."
                  },
                  "heading": {
                    "type": "string",
                    "description": "Up to 160 characters; \"Stay in touch\" if left out."
                  },
                  "description": {
                    "type": "string",
                    "description": "Up to 600 characters."
                  },
                  "buttonLabel": {
                    "type": "string",
                    "description": "Up to 40 characters; \"Subscribe\" if left out."
                  },
                  "consentText": {
                    "type": "string",
                    "description": "What the person agrees to, 10 to 1,000 characters, recorded word for word on every contact. A sensible default if left out."
                  },
                  "askName": {
                    "type": "boolean",
                    "description": "Ask for a name as well as an address. true if left out."
                  },
                  "doubleOptIn": {
                    "type": "boolean",
                    "description": "Subscribe people only once they use the link mailed to them. true if left out."
                  },
                  "successMessage": {
                    "type": "string",
                    "description": "Shown after submitting, up to 300 characters."
                  },
                  "redirectUrl": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uri",
                    "description": "A page to send people to after submitting, instead of the message."
                  },
                  "replyTo": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "email",
                    "description": "Where replies to the confirmation email go."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 10 tags given to everyone who signs up: lower case letters, numbers and dashes."
                  },
                  "active": {
                    "type": "boolean",
                    "description": "Whether the form takes sign-ups. true if left out."
                  },
                  "allowedSites": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 20 host names the form may be shown on, like yourcompany.com; empty for anywhere. \"www.\" is dropped."
                  }
                }
              },
              "example": {
                "buttonLabel": "Sign me up",
                "successMessage": "Thanks. Check your inbox to confirm."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "a5f0dd2d-bfc1-4247-84fa-6a8ff0dd0740",
                  "public_id": "9QAqDsJMl79DfFKY",
                  "name": "API docs example",
                  "heading": "Get our monthly letter",
                  "description": "New products and studio notes, about once a month.",
                  "button_label": "Sign me up",
                  "consent_text": "I agree to receive emails from us. I can unsubscribe at any time with the link in every email.",
                  "ask_name": true,
                  "double_opt_in": true,
                  "success_message": "Thanks. Check your inbox to confirm.",
                  "redirect_url": null,
                  "reply_to": null,
                  "tags": [
                    "newsletter"
                  ],
                  "active": false,
                  "allowed_sites": [
                    "example.com"
                  ],
                  "created_at": "2026-10-30T06:14:07.200Z",
                  "updated_at": "2026-10-30T06:14:07.475Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "delete": {
        "operationId": "forms.delete",
        "summary": "Delete a form",
        "description": "Deletes a sign-up form. Its hosted link and every embed stop answering; the contacts it brought in stay in your audience and keep the record of what they agreed to, which is stored with them. Refused with 409 while an automation starts from the form, naming those automations: deleting the form would turn them into automations that start for every sign-up, so change or delete them first. 404 if the form is not in your account. Needs audience:write.",
        "tags": [
          "Forms"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The form's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "deleted": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/forms/{id}/check-install": {
      "post": {
        "operationId": "forms.check_install",
        "summary": "Check a form is on a page",
        "description": "Fetches a page of your site and looks for this form in it: placed with the script, a button that opens it, your own form connected to it, an iframe, or a link. Says how it was found and whether the script line is missing, or why it was not found. Only public pages can be fetched. Needs audience:read.",
        "tags": [
          "Forms"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The form's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "The page to look at, up to 2,000 characters; https:// is assumed if left off."
                  }
                },
                "required": [
                  "url"
                ]
              },
              "example": {
                "url": "https://example.com/"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "found": false,
                  "url": "https://example.com/",
                  "reason": "The form is not in this page as it was sent. If your site builds pages in the browser, it may still show once the page h..."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns": {
      "get": {
        "operationId": "campaigns.list",
        "summary": "List campaigns",
        "description": "Every campaign, newest first, with its state, whether its last check passed, and how many recipients it has and how many were sent. postalAddress is the account's, which every campaign carries. Needs audience:read.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "campaigns": [
                    {
                      "id": "9e210b02-8326-4122-a449-2196ccd8cc38",
                      "name": "API docs example",
                      "subject": "Our autumn collection is here",
                      "preheader": "Twelve new pieces, made in small batches.",
                      "from_name": "Northwind Traders",
                      "from_local": "news",
                      "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                      "domain": "northwind-local.test",
                      "reply_to": "hello@northwind-local.test",
                      "body": "",
                      "audience_tags": [
                        "vip"
                      ],
                      "segment": null,
                      "topic_id": "bea753b0-6132-4bc2-bc2a-18ff86ed0079",
                      "experiment": null,
                      "experiment_result": null,
                      "brief": {},
                      "updated_by": "key sa1pteyz44qbm",
                      "state": "sent",
                      "state_reason": null,
                      "scheduled_at": "2026-10-30T08:15:19.116Z",
                      "started_at": "2026-10-30T06:15:20.212Z",
                      "finished_at": "2026-10-30T06:15:20.411Z",
                      "created_at": "2026-10-30T06:14:34.949Z",
                      "updated_at": "2026-10-30T06:15:20.411Z",
                      "kind": "marketing",
                      "validation_ok": true,
                      "validation_blocking": 0,
                      "recipients": 0,
                      "sent": 0
                    }
                  ],
                  "postalAddress": "12 Studio Lane, Austin, TX 78701"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "post": {
        "operationId": "campaigns.create",
        "summary": "Create a campaign",
        "description": "Creates a draft. Its design starts from a template, from an email's HTML you send, or from a starter design, in your brand look unless you ask for the original. A domainId that is not one of yours is left empty. Set the topic, segment, subject test and brief afterwards with PATCH /campaigns/:id. Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Your name for the campaign, 1 to 120 characters."
                  },
                  "subject": {
                    "type": "string",
                    "description": "Up to 200 characters. From the imported HTML's title if left out."
                  },
                  "preheader": {
                    "type": "string",
                    "description": "The preview line, up to 200 characters."
                  },
                  "fromName": {
                    "type": "string",
                    "description": "Up to 100 characters."
                  },
                  "fromLocal": {
                    "type": "string",
                    "description": "The part of the from address before the @; \"news\" if left out."
                  },
                  "domainId": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid",
                    "description": "The sending domain."
                  },
                  "replyTo": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "email",
                    "description": "Where replies go."
                  },
                  "audienceTags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 20 tags; the campaign goes to subscribed contacts with any of them, or everyone if empty."
                  },
                  "templateId": {
                    "type": "string",
                    "description": "A built in template (\"builtin:...\") or one of your own, as the starting design."
                  },
                  "look": {
                    "type": "string",
                    "enum": [
                      "brand",
                      "original"
                    ],
                    "description": "Start in your brand look (\"brand\", the default) or the template's own."
                  },
                  "html": {
                    "type": "string",
                    "description": "An existing email's HTML, up to 900,000 characters, read into the design (see POST /campaigns/import-html)."
                  },
                  "body": {
                    "type": "string",
                    "description": "Plain body text in the older body language, up to 100,000 characters; leave it out to start from a design."
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "API docs example",
                "subject": "Our autumn collection is here",
                "preheader": "Twelve new pieces, made in small batches.",
                "fromName": "Northwind Traders",
                "fromLocal": "news",
                "domainId": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                "replyTo": "hello@northwind-local.test",
                "audienceTags": [
                  "vip"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "9e210b02-8326-4122-a449-2196ccd8cc38",
                  "name": "API docs example",
                  "subject": "Our autumn collection is here",
                  "preheader": "Twelve new pieces, made in small batches.",
                  "from_name": "Northwind Traders",
                  "from_local": "news",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": "hello@northwind-local.test",
                  "body": "",
                  "audience_tags": [
                    "vip"
                  ],
                  "segment": null,
                  "topic_id": null,
                  "experiment": null,
                  "experiment_result": null,
                  "brief": {},
                  "updated_by": null,
                  "state": "draft",
                  "state_reason": null,
                  "scheduled_at": null,
                  "started_at": null,
                  "finished_at": null,
                  "created_at": "2026-10-30T06:14:34.949Z",
                  "updated_at": "2026-10-30T06:14:34.949Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/import-html": {
      "post": {
        "operationId": "campaigns.import_html",
        "summary": "Read an email's HTML",
        "description": "Reads an existing email's HTML into a design without creating anything, and says what came across and what was left out, so you can check it before starting a campaign from it (send the same html to POST /campaigns). Up to 900,000 characters. Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "html": {
                    "type": "string",
                    "description": "The email's HTML."
                  }
                },
                "required": [
                  "html"
                ]
              },
              "example": {
                "html": "<html><head><title>Autumn sale</title></head><body><h1>Autumn sale</h1><p>Hi there, everything in the shop is 20% off this week.</p><a href=\"https://northwind-local.test/sale\" style=\"background:#0f766e;color:#fff;padding:12px 20px\">Shop the sale</a></body></html>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "design": {
                    "version": 1,
                    "theme": {
                      "background": "#f4f6fb",
                      "content": "#ffffff",
                      "text": "#2b3245",
                      "heading": "#0b0d14",
                      "accent": "#0f766e",
                      "onAccent": "#ffffff",
                      "muted": "#7a8296",
                      "font": "system",
                      "radius": 12
                    },
                    "blocks": [
                      {
                        "id": "b-mvukw77w-5",
                        "paddingTop": 0,
                        "paddingBottom": 16,
                        "background": "",
                        "hideOnMobile": false,
                        "type": "heading",
                        "text": "Autumn sale",
                        "level": 1,
                        "align": "left",
                        "color": ""
                      },
                      {
                        "id": "b-mvukw77w-6",
                        "paddingTop": 0,
                        "paddingBottom": 16,
                        "background": "",
                        "hideOnMobile": false,
                        "type": "text",
                        "text": "Hi there, everything in the shop is 20% off this week.",
                        "align": "left",
                        "size": 16,
                        "color": ""
                      }
                    ],
                    "footerNote": "",
                    "plainText": ""
                  },
                  "title": "Autumn sale",
                  "preheader": "",
                  "counts": {
                    "headings": 1,
                    "paragraphs": 1,
                    "images": 0,
                    "buttons": 1
                  },
                  "notes": [
                    "The layout is now the Studio’s own: check the order, and set colours and fonts in Email style."
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}": {
      "get": {
        "operationId": "campaigns.get",
        "summary": "Get a campaign",
        "description": "One campaign, with its recipients by state, opens and clicks, and how many people its audience reaches now. Needs audience:read.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "9e210b02-8326-4122-a449-2196ccd8cc38",
                  "name": "API docs example",
                  "subject": "Our autumn collection is here",
                  "preheader": "Twelve new pieces, made in small batches.",
                  "from_name": "Northwind Traders",
                  "from_local": "news",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": "hello@northwind-local.test",
                  "body": "",
                  "audience_tags": [
                    "vip"
                  ],
                  "segment": null,
                  "topic_id": "bea753b0-6132-4bc2-bc2a-18ff86ed0079",
                  "experiment": null,
                  "experiment_result": null,
                  "brief": {},
                  "updated_by": "key sa1pteyz44qbm",
                  "state": "draft",
                  "state_reason": null,
                  "scheduled_at": null,
                  "started_at": null,
                  "finished_at": null,
                  "created_at": "2026-10-30T06:14:34.949Z",
                  "updated_at": "2026-10-30T06:14:45.827Z",
                  "stats": {},
                  "engagement": {
                    "opened": 0,
                    "clicked": 0
                  },
                  "audienceSize": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "patch": {
        "operationId": "campaigns.update",
        "summary": "Update a campaign",
        "description": "Changes a draft; send only what changes. Anything but a draft answers 409 (cancel a scheduled campaign to edit it). A topicId that is not one of yours answers 400. The brief is merged field by field. Changing anything after approval means approving again before it can be scheduled. Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1 to 120 characters."
                  },
                  "subject": {
                    "type": "string",
                    "description": "Up to 200 characters."
                  },
                  "preheader": {
                    "type": "string",
                    "description": "Up to 200 characters."
                  },
                  "fromName": {
                    "type": "string",
                    "description": "Up to 100 characters."
                  },
                  "fromLocal": {
                    "type": "string",
                    "description": "The part of the from address before the @."
                  },
                  "domainId": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid",
                    "description": "The sending domain; one that is not yours is left empty."
                  },
                  "replyTo": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "email",
                    "description": "Where replies go."
                  },
                  "audienceTags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 20 tags."
                  },
                  "segment": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "description": "Rules the audience must match: { match: \"all\" | \"any\", rules: [...] }, with rules on tags, join date, form, source, past campaigns, attributes and name."
                  },
                  "topicId": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid",
                    "description": "The topic it belongs to; people who opted out of it are left out."
                  },
                  "experiment": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "description": "A subject test: { variants: [{ key: \"B\", subject }], testShare, metric: \"clicks\" | \"opens\", windowHours, minPerVariant }."
                  },
                  "brief": {
                    "type": "object",
                    "description": "Notes for writing help: goal, audience, offer, action, tone, sourceUrl, sourceNotes. An empty value removes its field."
                  },
                  "body": {
                    "type": "string",
                    "description": "Plain body text in the older body language; it replaces the design."
                  }
                }
              },
              "example": {
                "subject": "Our autumn collection is here",
                "topicId": "bea753b0-6132-4bc2-bc2a-18ff86ed0079"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "9e210b02-8326-4122-a449-2196ccd8cc38",
                  "name": "API docs example",
                  "subject": "Our autumn collection is here",
                  "preheader": "Twelve new pieces, made in small batches.",
                  "from_name": "Northwind Traders",
                  "from_local": "news",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": "hello@northwind-local.test",
                  "body": "",
                  "audience_tags": [
                    "vip"
                  ],
                  "segment": null,
                  "topic_id": "bea753b0-6132-4bc2-bc2a-18ff86ed0079",
                  "experiment": null,
                  "experiment_result": null,
                  "brief": {},
                  "updated_by": "key sa1pteyz44qbm",
                  "state": "draft",
                  "state_reason": null,
                  "scheduled_at": null,
                  "started_at": null,
                  "finished_at": null,
                  "created_at": "2026-10-30T06:14:34.949Z",
                  "updated_at": "2026-10-30T06:14:45.827Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "delete": {
        "operationId": "campaigns.delete",
        "summary": "Delete a campaign",
        "description": "Deletes a draft that never went out, with its versions and history. Anything that started sending is kept as a record and answers 409. Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "deleted": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/studio": {
      "get": {
        "operationId": "campaigns.design",
        "summary": "Get a campaign's design",
        "description": "The campaign's design (theme and blocks), whether its approval still holds, who its audience reaches and who is left out and why, the personal fields it uses, and its last check. Needs audience:read.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "design": {
                    "version": 1,
                    "theme": {
                      "background": "#f4f6fb",
                      "content": "#ffffff",
                      "text": "#2b3245",
                      "heading": "#052e2b",
                      "accent": "#0f766e",
                      "onAccent": "#ffffff",
                      "muted": "#7a8296",
                      "font": "serif",
                      "radius": 12
                    },
                    "blocks": [
                      {
                        "id": "b-mvukur45-1",
                        "paddingTop": 0,
                        "paddingBottom": 16,
                        "background": "",
                        "hideOnMobile": false,
                        "type": "header",
                        "logoSrc": "",
                        "logoAlt": "Northwind Traders",
                        "logoWidth": 140,
                        "text": "Northwind Traders",
                        "align": "center"
                      },
                      {
                        "id": "b-mvukur45-2",
                        "paddingTop": 0,
                        "paddingBottom": 16,
                        "background": "",
                        "hideOnMobile": false,
                        "type": "heading",
                        "text": "A headline that says what is new",
                        "level": 1,
                        "align": "left",
                        "color": ""
                      }
                    ],
                    "footerNote": "",
                    "plainText": ""
                  },
                  "approval": {
                    "holds": false,
                    "versionId": null,
                    "number": null
                  },
                  "audience": {
                    "matching": 1,
                    "eligible": 0,
                    "topic_opted_out": 1,
                    "suppressed": 0,
                    "unconfirmed": 0,
                    "unsubscribed": 0,
                    "unnamed": 0,
                    "invalid": 0
                  },
                  "fields": [
                    "first_name",
                    "name"
                  ],
                  "validation": null,
                  "updatedBy": "key sa1pteyz44qbm",
                  "updatedAt": "2026-10-30T06:14:35.021Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/design": {
      "put": {
        "operationId": "campaigns.save_design",
        "summary": "Save a campaign's design",
        "description": "Replaces a draft's design with the one sent, checked against the design schema (version, theme, blocks, footerNote, plainText; start from GET /campaigns/:id/studio). Anything but a draft answers 409. A design changed after approval must be approved again. A custom HTML block ({ type: \"html\", html }, at most 50 KB) is stored only as the sanitiser leaves it; the answer lists each one under html with the HTML kept and what was removed. Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "design": {
                    "type": "object",
                    "description": "The whole design, as GET /campaigns/:id/studio returns it."
                  }
                },
                "required": [
                  "design"
                ]
              },
              "example": {
                "design": {
                  "version": 1,
                  "theme": {
                    "background": "#f4f6fb",
                    "content": "#ffffff",
                    "text": "#2b3245",
                    "heading": "#052e2b",
                    "accent": "#0f766e",
                    "onAccent": "#ffffff",
                    "muted": "#7a8296",
                    "font": "serif",
                    "radius": 12
                  },
                  "blocks": [
                    {
                      "id": "b-mvukur45-1",
                      "paddingTop": 0,
                      "paddingBottom": 16,
                      "background": "",
                      "hideOnMobile": false,
                      "type": "header",
                      "logoSrc": "",
                      "logoAlt": "Northwind Traders",
                      "logoWidth": 140,
                      "text": "Northwind Traders",
                      "align": "center"
                    },
                    {
                      "id": "b-mvukur45-2",
                      "paddingTop": 0,
                      "paddingBottom": 16,
                      "background": "",
                      "hideOnMobile": false,
                      "type": "heading",
                      "text": "Our autumn collection is here",
                      "level": 1,
                      "align": "left",
                      "color": ""
                    },
                    {
                      "id": "b-mvukur45-3",
                      "paddingTop": 0,
                      "paddingBottom": 16,
                      "background": "",
                      "hideOnMobile": false,
                      "type": "text",
                      "text": "Hi {{ name | there }},\n\nTwelve new pieces, made in small batches in our Austin studio.",
                      "align": "left",
                      "size": 16,
                      "color": ""
                    },
                    {
                      "id": "b-mvukur45-4",
                      "paddingTop": 0,
                      "paddingBottom": 16,
                      "background": "",
                      "hideOnMobile": false,
                      "type": "button",
                      "label": "See the collection",
                      "href": "https://northwind-local.test/autumn",
                      "align": "left",
                      "style": "filled",
                      "color": ""
                    }
                  ],
                  "footerNote": "",
                  "plainText": ""
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "savedAt": "2026-10-30T06:15:03.020Z",
                  "html": []
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/validate": {
      "post": {
        "operationId": "campaigns.validate",
        "summary": "Check a campaign",
        "description": "Runs the checks a campaign must pass before it can be approved: blocking problems (placeholder text, links that go nowhere, an empty audience and the like) and advice. With deep, every link and image is fetched too. Needs audience:read.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "deep": {
                    "type": "boolean",
                    "description": "Also fetch each link and image. false if left out."
                  }
                }
              },
              "example": {
                "deep": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "report": {
                    "ok": true,
                    "blocking": [],
                    "advisory": [
                      {
                        "code": "plan-campaigns",
                        "area": "delivery",
                        "message": "Without Campaigns, forms and automation you can send 461 more campaign emails in this 30 days; this one goes to 1.",
                        "fix": "Turn it on in Billing to send without this limit."
                      }
                    ],
                    "checkedAt": "2026-10-30T06:15:03.080Z"
                  },
                  "audience": {
                    "matching": 1,
                    "eligible": 1,
                    "topic_opted_out": 0,
                    "suppressed": 0,
                    "unconfirmed": 0,
                    "unsubscribed": 0,
                    "unnamed": 0,
                    "invalid": 0
                  },
                  "bytes": 3667,
                  "fields": [
                    "name"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/render": {
      "get": {
        "operationId": "campaigns.render",
        "summary": "Render a campaign",
        "description": "The message as a recipient would see it, as HTML or plain text (not JSON): for a sample person, one of your contacts, someone with no name (to see the fallbacks) or a very long name. The unsubscribe link is a placeholder. Needs audience:read.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "html if left out.",
            "schema": {
              "type": "string",
              "enum": [
                "html",
                "text"
              ]
            }
          },
          {
            "name": "as",
            "in": "query",
            "required": false,
            "description": "Who it is rendered for; sample if left out.",
            "schema": {
              "type": "string",
              "enum": [
                "sample",
                "noname",
                "long"
              ]
            }
          },
          {
            "name": "contactId",
            "in": "query",
            "required": false,
            "description": "Render it for this contact instead.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Northwind Traders\n\nOur autumn collection is here\n\nHi Alex,\n\nTwelve new pieces, made in small batches in our Austin studio.\n\nSee the collection: https://northwind-local.test/autumn\n\n--\nYou are receiving this because you subscribed to Northwind Traders.\nNorthwind Traders, 12 Studio Lane, Austin, TX 78701\nUnsubscribe: #unsubscribe"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/test": {
      "post": {
        "operationId": "campaigns.test",
        "summary": "Send a test",
        "description": "Sends one copy to each address, exactly as a send would compile it, with \"[Test]\" before the subject and an unsubscribe link that goes nowhere. Copies go only to people on your account (400 for anyone else), 30 an hour (429 beyond that). The campaign needs a sending domain that is set up (409). Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "to": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "1 to 5 addresses of people on your account."
                  }
                },
                "required": [
                  "to"
                ]
              },
              "example": {
                "to": [
                  "ui-test@rykonmail-local.test"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "results": [
                    {
                      "to": "ui-test@rykonmail-local.test",
                      "sent": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/approve": {
      "post": {
        "operationId": "campaigns.approve",
        "summary": "Approve a campaign",
        "description": "Approves the campaign exactly as it stands and keeps that version. Every blocking check must pass (409 with the report otherwise), and only a draft can be approved. Change anything afterwards and it must be approved again. Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "approved": true,
                  "version": 1,
                  "versionId": "1468cf84-2fb5-4a40-97c0-6edfb1926491"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/schedule": {
      "post": {
        "operationId": "campaigns.schedule",
        "summary": "Schedule or send a campaign",
        "description": "Sends now, or at a time. Only a draft whose approval still covers it as it stands can be scheduled (409 otherwise). Without the Campaigns add-on a campaign must fit in what is left of the free allowance, and with it the list must fit the plan; either answers 402. Scheduling twice never sends twice. Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "description": "When to send; now if null or left out."
                  }
                }
              },
              "example": {
                "at": "2026-10-30T08:15:19Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "9e210b02-8326-4122-a449-2196ccd8cc38",
                  "name": "API docs example",
                  "subject": "Our autumn collection is here",
                  "preheader": "Twelve new pieces, made in small batches.",
                  "from_name": "Northwind Traders",
                  "from_local": "news",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": "hello@northwind-local.test",
                  "body": "",
                  "audience_tags": [
                    "vip"
                  ],
                  "segment": null,
                  "topic_id": "bea753b0-6132-4bc2-bc2a-18ff86ed0079",
                  "experiment": null,
                  "experiment_result": null,
                  "brief": {},
                  "updated_by": "key sa1pteyz44qbm",
                  "state": "scheduled",
                  "state_reason": null,
                  "scheduled_at": "2026-10-30T08:15:18.947Z",
                  "started_at": null,
                  "finished_at": null,
                  "created_at": "2026-10-30T06:14:34.949Z",
                  "updated_at": "2026-10-30T06:15:19.947Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/pause": {
      "post": {
        "operationId": "campaigns.pause",
        "summary": "Pause a send",
        "description": "Stops a campaign part way: nothing still queued goes out; what was already handed to the sending service cannot be called back. \"held\" is how many copies wait. Only a campaign that is sending can be paused (409). Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "state": "paused",
                  "held": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/resume": {
      "post": {
        "operationId": "campaigns.resume",
        "summary": "Resume a send",
        "description": "Carries on sending a paused campaign from where it stopped. Only a paused campaign can be resumed (409). Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "state": "sending"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/cancel": {
      "post": {
        "operationId": "campaigns.cancel",
        "summary": "Cancel a campaign",
        "description": "A scheduled campaign that has not started goes back to being a draft; one that is sending or paused stops and is cancelled. Anything else answers 409. Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "9e210b02-8326-4122-a449-2196ccd8cc38",
                  "name": "API docs example",
                  "subject": "Our autumn collection is here",
                  "preheader": "Twelve new pieces, made in small batches.",
                  "from_name": "Northwind Traders",
                  "from_local": "news",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": "hello@northwind-local.test",
                  "body": "",
                  "audience_tags": [
                    "vip"
                  ],
                  "segment": null,
                  "topic_id": "bea753b0-6132-4bc2-bc2a-18ff86ed0079",
                  "experiment": null,
                  "experiment_result": null,
                  "brief": {},
                  "updated_by": "key sa1pteyz44qbm",
                  "state": "draft",
                  "state_reason": null,
                  "scheduled_at": null,
                  "started_at": null,
                  "finished_at": null,
                  "created_at": "2026-10-30T06:14:34.949Z",
                  "updated_at": "2026-10-30T06:15:20.041Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/duplicate": {
      "post": {
        "operationId": "campaigns.duplicate",
        "summary": "Duplicate a campaign",
        "description": "A new draft with the same design, settings and audience, named \"<name> (copy)\", for the next send. Answers with its id. Needs audience:write.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "bc95b28b-90e9-473c-93a4-bf8d79e4f3f6"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/report": {
      "get": {
        "operationId": "campaigns.report",
        "summary": "Get a campaign's report",
        "description": "What happened to a campaign: each measure with its definition and rate, clicks by link, a timeline, the subject test's result, progress, and plain observations comparing it with your usual results. Needs audience:read.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "observations": [
                    "Nothing has been delivered yet, so there is nothing to compare."
                  ],
                  "test": null,
                  "metrics": [
                    {
                      "key": "recipients",
                      "label": "Recipients",
                      "value": 2,
                      "rate": null,
                      "of": null,
                      "definition": "People who were eligible when sending started: subscribed, not suppressed, matching the audience."
                    },
                    {
                      "key": "submitted",
                      "label": "Sent",
                      "value": 2,
                      "rate": 1,
                      "of": "recipients",
                      "definition": "Messages accepted by our sending service. Not yet a delivery."
                    }
                  ],
                  "links": [],
                  "timeline": [],
                  "progress": {
                    "queued": 0,
                    "skipped": 0,
                    "failed": 0,
                    "firstSent": "2026-10-30T03:34:46.270Z",
                    "lastSent": "2026-10-30T03:34:46.274Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/campaigns/{id}/versions": {
      "get": {
        "operationId": "campaigns.versions",
        "summary": "List a campaign's versions",
        "description": "The campaign's saved versions, newest first (up to 100), with who made each and which were approved. Needs audience:read.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The campaign's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "versions": [
                    {
                      "id": "1468cf84-2fb5-4a40-97c0-6edfb1926491",
                      "number": 1,
                      "source": "approval",
                      "note": "approved",
                      "subject": "Our autumn collection is here",
                      "content_hash": "e1abd5b754f627e8d73e9727f1199fbab6a60d699c0dcf15dc79e57cd907aa7c",
                      "created_by": "key sa1pteyz44qbm",
                      "created_at": "2026-10-30T06:15:03.264Z",
                      "approved": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/automations": {
      "get": {
        "operationId": "automations.list",
        "summary": "List automations",
        "description": "The account's automations, newest first, with how many steps each has, how many people are in it now, how many have started it and how many emails it sent. Needs audience:read.",
        "tags": [
          "Automations"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "automations": [
                    {
                      "id": "77fcfb0a-d16e-4046-b3b1-cc1828553111",
                      "name": "API docs example",
                      "trigger_form_id": "a5f0dd2d-bfc1-4247-84fa-6a8ff0dd0740",
                      "trigger_form": "API docs example",
                      "trigger_tag": null,
                      "active": false,
                      "from_name": "Northwind Traders",
                      "from_local": "hello",
                      "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                      "domain": "northwind-local.test",
                      "reply_to": null,
                      "created_at": "2026-10-30T06:15:53.563Z",
                      "updated_at": "2026-10-30T06:15:53.698Z",
                      "emails": 3,
                      "running": 0,
                      "started": 0,
                      "sent": 0
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "post": {
        "operationId": "automations.create",
        "summary": "Create an automation",
        "description": "Creates an automation, switched off, that starts with one empty welcome email sent as soon as someone subscribes, from your first domain that is set up for sending. Fill it in with PUT /automations/:id. Needs audience:write.",
        "tags": [
          "Automations"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1 to 120 characters."
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "API docs example"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "77fcfb0a-d16e-4046-b3b1-cc1828553111",
                  "name": "API docs example",
                  "trigger_form_id": null,
                  "trigger_form": null,
                  "trigger_tag": null,
                  "active": false,
                  "from_name": "",
                  "from_local": "hello",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": null,
                  "created_at": "2026-10-30T06:15:53.563Z",
                  "updated_at": "2026-10-30T06:15:53.563Z",
                  "steps": [
                    {
                      "id": "73606f24-166c-446c-9b55-94278a975061",
                      "position": 0,
                      "kind": "email",
                      "condition": "always",
                      "condition_value": null,
                      "tags_add": [],
                      "tags_remove": [],
                      "field_key": null,
                      "field_value": null,
                      "notify_to": null,
                      "delay_minutes": 0,
                      "subject": "",
                      "preheader": "",
                      "body": "",
                      "sent": 0,
                      "delivered": 0,
                      "bounced": 0,
                      "complained": 0,
                      "failed": 0,
                      "skipped": 0,
                      "opened": 0,
                      "clicked": 0
                    }
                  ],
                  "runs": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/automations/{id}": {
      "get": {
        "operationId": "automations.get",
        "summary": "Get an automation",
        "description": "One automation, with every step and its results (sent, delivered, opened, clicked, skipped and so on) and its people by state. Needs audience:read.",
        "tags": [
          "Automations"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The automation's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "77fcfb0a-d16e-4046-b3b1-cc1828553111",
                  "name": "API docs example",
                  "trigger_form_id": "a5f0dd2d-bfc1-4247-84fa-6a8ff0dd0740",
                  "trigger_form": "API docs example",
                  "trigger_tag": null,
                  "active": false,
                  "from_name": "Northwind Traders",
                  "from_local": "hello",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": null,
                  "created_at": "2026-10-30T06:15:53.563Z",
                  "updated_at": "2026-10-30T06:15:53.698Z",
                  "steps": [
                    {
                      "id": "73606f24-166c-446c-9b55-94278a975061",
                      "position": 0,
                      "kind": "email",
                      "condition": "always",
                      "condition_value": null,
                      "tags_add": [],
                      "tags_remove": [],
                      "field_key": null,
                      "field_value": null,
                      "notify_to": null,
                      "delay_minutes": 0,
                      "subject": "Welcome to Northwind Traders",
                      "preheader": "",
                      "body": "Hi {{ name | there }},\n\nThanks for subscribing. Here is what to expect: one letter a month, never more.",
                      "sent": 0,
                      "delivered": 0,
                      "bounced": 0,
                      "complained": 0,
                      "failed": 0,
                      "skipped": 0,
                      "opened": 0,
                      "clicked": 0
                    },
                    {
                      "id": "17b3a766-54af-4fd5-b54b-54f6a552cad1",
                      "position": 1,
                      "kind": "email",
                      "condition": "not_opened",
                      "condition_value": null,
                      "tags_add": [],
                      "tags_remove": [],
                      "field_key": null,
                      "field_value": null,
                      "notify_to": null,
                      "delay_minutes": 4320,
                      "subject": "In case you missed it",
                      "preheader": "",
                      "body": "Hi {{ name | there }},\n\nA quick reminder of what is new this month.",
                      "sent": 0,
                      "delivered": 0,
                      "bounced": 0,
                      "complained": 0,
                      "failed": 0,
                      "skipped": 0,
                      "opened": 0,
                      "clicked": 0
                    }
                  ],
                  "runs": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "put": {
        "operationId": "automations.update",
        "summary": "Save an automation",
        "description": "Saves the settings and the whole sequence of steps; send them all. A step is an email, a handover to a person (notify), a tag change, a field change or the end, each after a wait, and may depend on whether the previous email was opened or clicked or on a tag. Send a step's id to keep it (and its history) when steps move. An email that has already been sent cannot be removed (409). A handover goes only to someone on the account or an address at one of its domains (400). The trigger form and the domain must be yours (400). People part way through carry on from the step they were going to do next. Needs audience:write.",
        "tags": [
          "Automations"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The automation's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1 to 120 characters."
                  },
                  "triggerFormId": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid",
                    "description": "Start for people who join through this form; null for any form."
                  },
                  "triggerTag": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Start only for people with this tag."
                  },
                  "fromName": {
                    "type": "string",
                    "description": "Up to 100 characters."
                  },
                  "fromLocal": {
                    "type": "string",
                    "description": "The part of the from address before the @."
                  },
                  "domainId": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid",
                    "description": "The sending domain."
                  },
                  "replyTo": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "email",
                    "description": "Where replies go."
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "1 to 20 steps: id, kind (\"email\", \"notify\", \"tag\", \"field\", \"end\"), condition (\"always\", \"opened\", \"not_opened\", \"clicked\", \"not_clicked\", \"has_tag\", \"lacks_tag\"), conditionValue, delayMinutes (required, up to 525,600), subject, preheader, body, notifyTo, tagsAdd, tagsRemove, fieldKey, fieldValue."
                  }
                },
                "required": [
                  "name",
                  "triggerFormId",
                  "triggerTag",
                  "fromName",
                  "fromLocal",
                  "domainId",
                  "replyTo",
                  "steps"
                ]
              },
              "example": {
                "name": "API docs example",
                "triggerFormId": "a5f0dd2d-bfc1-4247-84fa-6a8ff0dd0740",
                "triggerTag": null,
                "fromName": "Northwind Traders",
                "fromLocal": "hello",
                "domainId": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                "replyTo": null,
                "steps": [
                  {
                    "id": "73606f24-166c-446c-9b55-94278a975061",
                    "kind": "email",
                    "delayMinutes": 0,
                    "subject": "Welcome to Northwind Traders",
                    "body": "Hi {{ name | there }},\n\nThanks for subscribing. Here is what to expect: one letter a month, never more."
                  },
                  {
                    "kind": "email",
                    "condition": "not_opened",
                    "delayMinutes": 4320,
                    "subject": "In case you missed it",
                    "body": "Hi {{ name | there }},\n\nA quick reminder of what is new this month."
                  },
                  {
                    "kind": "tag",
                    "delayMinutes": 0,
                    "tagsAdd": [
                      "onboarded"
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "77fcfb0a-d16e-4046-b3b1-cc1828553111",
                  "name": "API docs example",
                  "trigger_form_id": "a5f0dd2d-bfc1-4247-84fa-6a8ff0dd0740",
                  "trigger_form": "API docs example",
                  "trigger_tag": null,
                  "active": false,
                  "from_name": "Northwind Traders",
                  "from_local": "hello",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": null,
                  "created_at": "2026-10-30T06:15:53.563Z",
                  "updated_at": "2026-10-30T06:15:53.637Z",
                  "steps": [
                    {
                      "id": "73606f24-166c-446c-9b55-94278a975061",
                      "position": 0,
                      "kind": "email",
                      "condition": "always",
                      "condition_value": null,
                      "tags_add": [],
                      "tags_remove": [],
                      "field_key": null,
                      "field_value": null,
                      "notify_to": null,
                      "delay_minutes": 0,
                      "subject": "Welcome to Northwind Traders",
                      "preheader": "",
                      "body": "Hi {{ name | there }},\n\nThanks for subscribing. Here is what to expect: one letter a month, never more.",
                      "sent": 0,
                      "delivered": 0,
                      "bounced": 0,
                      "complained": 0,
                      "failed": 0,
                      "skipped": 0,
                      "opened": 0,
                      "clicked": 0
                    },
                    {
                      "id": "17b3a766-54af-4fd5-b54b-54f6a552cad1",
                      "position": 1,
                      "kind": "email",
                      "condition": "not_opened",
                      "condition_value": null,
                      "tags_add": [],
                      "tags_remove": [],
                      "field_key": null,
                      "field_value": null,
                      "notify_to": null,
                      "delay_minutes": 4320,
                      "subject": "In case you missed it",
                      "preheader": "",
                      "body": "Hi {{ name | there }},\n\nA quick reminder of what is new this month.",
                      "sent": 0,
                      "delivered": 0,
                      "bounced": 0,
                      "complained": 0,
                      "failed": 0,
                      "skipped": 0,
                      "opened": 0,
                      "clicked": 0
                    }
                  ],
                  "runs": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "delete": {
        "operationId": "automations.delete",
        "summary": "Delete an automation",
        "description": "Deletes an automation nobody has been through. Once people have, its history is kept and this answers 409; pause it instead. Needs audience:write.",
        "tags": [
          "Automations"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The automation's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/automations/{id}/activate": {
      "post": {
        "operationId": "automations.activate",
        "summary": "Switch an automation on",
        "description": "Switches it on for people who subscribe from now; those already on the list are not mailed. It needs a sending domain that is set up (409), the account's postal address (400), a subject and body on every email and someone to tell on every handover (400). Needs audience:write.",
        "tags": [
          "Automations"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The automation's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "77fcfb0a-d16e-4046-b3b1-cc1828553111",
                  "name": "API docs example",
                  "trigger_form_id": "a5f0dd2d-bfc1-4247-84fa-6a8ff0dd0740",
                  "trigger_form": "API docs example",
                  "trigger_tag": null,
                  "active": true,
                  "from_name": "Northwind Traders",
                  "from_local": "hello",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": null,
                  "created_at": "2026-10-30T06:15:53.563Z",
                  "updated_at": "2026-10-30T06:15:53.681Z",
                  "steps": [
                    {
                      "id": "73606f24-166c-446c-9b55-94278a975061",
                      "position": 0,
                      "kind": "email",
                      "condition": "always",
                      "condition_value": null,
                      "tags_add": [],
                      "tags_remove": [],
                      "field_key": null,
                      "field_value": null,
                      "notify_to": null,
                      "delay_minutes": 0,
                      "subject": "Welcome to Northwind Traders",
                      "preheader": "",
                      "body": "Hi {{ name | there }},\n\nThanks for subscribing. Here is what to expect: one letter a month, never more.",
                      "sent": 0,
                      "delivered": 0,
                      "bounced": 0,
                      "complained": 0,
                      "failed": 0,
                      "skipped": 0,
                      "opened": 0,
                      "clicked": 0
                    },
                    {
                      "id": "17b3a766-54af-4fd5-b54b-54f6a552cad1",
                      "position": 1,
                      "kind": "email",
                      "condition": "not_opened",
                      "condition_value": null,
                      "tags_add": [],
                      "tags_remove": [],
                      "field_key": null,
                      "field_value": null,
                      "notify_to": null,
                      "delay_minutes": 4320,
                      "subject": "In case you missed it",
                      "preheader": "",
                      "body": "Hi {{ name | there }},\n\nA quick reminder of what is new this month.",
                      "sent": 0,
                      "delivered": 0,
                      "bounced": 0,
                      "complained": 0,
                      "failed": 0,
                      "skipped": 0,
                      "opened": 0,
                      "clicked": 0
                    }
                  ],
                  "runs": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/automations/{id}/pause": {
      "post": {
        "operationId": "automations.pause",
        "summary": "Pause an automation",
        "description": "Nobody new starts, and nobody already in it is sent anything until it is switched on again. Needs audience:write.",
        "tags": [
          "Automations"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The automation's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "77fcfb0a-d16e-4046-b3b1-cc1828553111",
                  "name": "API docs example",
                  "trigger_form_id": "a5f0dd2d-bfc1-4247-84fa-6a8ff0dd0740",
                  "trigger_form": "API docs example",
                  "trigger_tag": null,
                  "active": false,
                  "from_name": "Northwind Traders",
                  "from_local": "hello",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "domain": "northwind-local.test",
                  "reply_to": null,
                  "created_at": "2026-10-30T06:15:53.563Z",
                  "updated_at": "2026-10-30T06:15:53.698Z",
                  "steps": [
                    {
                      "id": "73606f24-166c-446c-9b55-94278a975061",
                      "position": 0,
                      "kind": "email",
                      "condition": "always",
                      "condition_value": null,
                      "tags_add": [],
                      "tags_remove": [],
                      "field_key": null,
                      "field_value": null,
                      "notify_to": null,
                      "delay_minutes": 0,
                      "subject": "Welcome to Northwind Traders",
                      "preheader": "",
                      "body": "Hi {{ name | there }},\n\nThanks for subscribing. Here is what to expect: one letter a month, never more.",
                      "sent": 0,
                      "delivered": 0,
                      "bounced": 0,
                      "complained": 0,
                      "failed": 0,
                      "skipped": 0,
                      "opened": 0,
                      "clicked": 0
                    },
                    {
                      "id": "17b3a766-54af-4fd5-b54b-54f6a552cad1",
                      "position": 1,
                      "kind": "email",
                      "condition": "not_opened",
                      "condition_value": null,
                      "tags_add": [],
                      "tags_remove": [],
                      "field_key": null,
                      "field_value": null,
                      "notify_to": null,
                      "delay_minutes": 4320,
                      "subject": "In case you missed it",
                      "preheader": "",
                      "body": "Hi {{ name | there }},\n\nA quick reminder of what is new this month.",
                      "sent": 0,
                      "delivered": 0,
                      "bounced": 0,
                      "complained": 0,
                      "failed": 0,
                      "skipped": 0,
                      "opened": 0,
                      "clicked": 0
                    }
                  ],
                  "runs": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/automations/{id}/runs": {
      "get": {
        "operationId": "automations.runs",
        "summary": "List an automation's people",
        "description": "Each person's progress, newest first (up to 200): where they are, when their next step is due, what each step did, or why they stopped. Needs audience:read.",
        "tags": [
          "Automations"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "audience:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The automation's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Only people in this state.",
            "schema": {
              "type": "string",
              "enum": [
                "running",
                "completed",
                "exited",
                "failed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "runs": [
                    {
                      "id": "d94cbb6d-481e-46e7-bd38-3fb48b6e643f",
                      "email": "riley.1793252140@reader-local.test",
                      "name": "Riley Chen",
                      "state": "completed",
                      "next_position": 2,
                      "next_at": "2026-10-29T05:42:17.604Z",
                      "exit_reason": null,
                      "waiting_reason": null,
                      "started_at": "2026-10-29T05:36:05.795Z",
                      "finished_at": "2026-10-29T05:37:17.637Z",
                      "sends": [
                        {
                          "position": 0,
                          "state": "sent",
                          "sentAt": "2026-10-29T05:36:16.998971+00:00",
                          "error": null
                        },
                        {
                          "position": 1,
                          "state": "skipped",
                          "sentAt": "2026-10-29T05:36:47.308649+00:00",
                          "error": "condition not met: not opened"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/domains": {
      "get": {
        "operationId": "domains.list",
        "summary": "List domains",
        "description": "The account's domains, newest first, with their state, whether their DNS has drifted, and whether ownership is proven. Needs domains:read.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "domains:read",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "domains": [
                    {
                      "id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                      "tenant_id": "7024c88d-abfb-4555-bd16-530a53d2c22f",
                      "name": "northwind-local.test",
                      "state": "active",
                      "state_reason": null,
                      "dns_mode": "external",
                      "verified_at": null,
                      "observed_at": null,
                      "drifted": false,
                      "drift_since": null,
                      "created_at": "2026-10-29T05:14:24.823Z",
                      "owned": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "post": {
        "operationId": "domains.create",
        "summary": "Add a domain",
        "description": "Adds a domain and starts setting it up; it answers 202 with the job, because setup waits on DNS. First publish the ownership record it returns: nothing is configured for the domain until that record is seen, and then the mail records to publish appear on GET /domains/:id. Retrying joins the setup already running. A domain already on your account or registered on the platform answers 409, as does one this platform runs on. Your plan sets how many domains you can have (409 beyond that). Needs domains:write.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "domains:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "The domain name, like yourcompany.com."
                  },
                  "dnsMode": {
                    "type": "string",
                    "enum": [
                      "external",
                      "delegated"
                    ],
                    "description": "Who hosts the DNS; external (yours) if left out."
                  },
                  "quotas": {
                    "type": "object",
                    "description": "Optional limits for the domain: maxMailboxes, defaultQuotaMb, maxQuotaMb, domainQuotaMb."
                  }
                },
                "required": [
                  "domain"
                ]
              },
              "example": {
                "domain": "api-docs-example.test"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "a463c960-1309-4174-b629-b03ff1d6ba1c",
                  "domain": "api-docs-example.test",
                  "state": "ownership_pending",
                  "ownership": {
                    "kind": "TXT",
                    "name": "_rykonmail.api-docs-example.test",
                    "value": "rykonmail-verification=fwvhweev823wa8j4tmq4fm6yzd5vm8ye",
                    "purpose": "Proves this domain is yours. Nothing is set up until it is seen.",
                    "verified": false,
                    "verifiedAt": null
                  },
                  "job": {
                    "id": "40b62db3-14f6-466d-905a-ee2d9218c38c",
                    "state": "queued"
                  },
                  "next": "Publish the ownership record. Nothing is configured for this domain until it is seen, and then the mail records follow."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/domains/{id}": {
      "get": {
        "operationId": "domains.get",
        "summary": "Get a domain",
        "description": "One domain: the ownership record, the records to publish and what was last seen of each, the records still outstanding, the sending identity, where its mailboxes connect, its recent setup jobs and a plain summary of where it stands. Needs domains:read.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "domains:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The domain's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "a463c960-1309-4174-b629-b03ff1d6ba1c",
                  "tenant_id": "7024c88d-abfb-4555-bd16-530a53d2c22f",
                  "name": "api-docs-example.test",
                  "state": "ownership_pending",
                  "state_reason": null,
                  "dns_mode": "external",
                  "desired_records": [],
                  "observed_records": [],
                  "observed_at": null,
                  "verified_at": null,
                  "drift": null,
                  "drift_since": null,
                  "ownership_verified_at": null,
                  "created_at": "2026-10-30T06:16:36.079Z",
                  "ownership": {
                    "kind": "TXT",
                    "name": "_rykonmail.api-docs-example.test",
                    "value": "rykonmail-verification=fwvhweev823wa8j4tmq4fm6yzd5vm8ye",
                    "purpose": "Proves this domain is yours. Nothing is set up until it is seen.",
                    "verified": false,
                    "verifiedAt": null
                  },
                  "mailHost": null,
                  "webmailUrl": "https://mail.rykonmail.com/",
                  "sendingIdentity": null,
                  "outstanding": [],
                  "summary": "Waiting for the ownership record.",
                  "jobs": [
                    {
                      "id": "40b62db3-14f6-466d-905a-ee2d9218c38c",
                      "operation": "domain.provision",
                      "state": "queued",
                      "wait_reason": null,
                      "failure_reason": null,
                      "attempts": 0,
                      "needs_operator": false,
                      "created_at": "2026-10-30T06:16:36.079Z",
                      "finished_at": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "delete": {
        "operationId": "domains.delete",
        "summary": "Remove a domain",
        "description": "Removes a domain from your account and from every backend: the mail store, the sending identity and the relay, so mail to it no longer arrives here and nothing is sent from it. Because that cannot be undone, the body must name the domain in confirm (400 if it is missing, 409 if it does not match). Refused with 409 while the domain still has mailboxes (the message names up to five; delete them first, since each one holds mail) or while a campaign is scheduled, sending or paused from it. In the console only the owner or an admin may remove a domain. Needs domains:write.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "domains:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The domain's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm": {
                    "type": "string",
                    "description": "The domain name, typed out."
                  }
                },
                "required": [
                  "confirm"
                ]
              },
              "example": {
                "confirm": "example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "removed": true,
                  "name": "example.com"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/domains/{id}/verify": {
      "post": {
        "operationId": "domains.verify",
        "summary": "Check a domain now",
        "description": "Checks the domain's DNS now instead of waiting for the next sweep, and answers 202 with the job. While setup is still running it is brought forward (\"nudged\"); setup that stopped is started again (\"retried\"), at most once a minute (409 sooner). Needs domains:write.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "domains:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The domain's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "job": {
                    "id": "40b62db3-14f6-466d-905a-ee2d9218c38c"
                  },
                  "nudged": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/domains/{id}/setup": {
      "get": {
        "operationId": "domains.setup",
        "summary": "Get a domain's DNS setup options",
        "description": "Who hosts the domain's DNS, whether a DNS provider is connected, and whether the automatic ways to publish the records (a Cloudflare token, Domain Connect) are open for it. It asks the domain's nameservers, so fetch it once rather than polling. Needs domains:read.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "domains:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The domain's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "zone": "northwind-local.test",
                  "nameservers": [],
                  "provider": null,
                  "recordsReady": false,
                  "connection": null,
                  "cloudflare": {
                    "available": true,
                    "reason": null
                  },
                  "domainConnect": {
                    "available": false,
                    "provider": null,
                    "reason": "Domain Connect is off on simulated backends: it would publish records the simulation made up."
                  },
                  "simulated": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/mailboxes": {
      "get": {
        "operationId": "mailboxes.list",
        "summary": "List mailboxes",
        "description": "The account's mailboxes, by address, with their quota, use, where they connect and which belong to an agent. Needs mailboxes:read.",
        "tags": [
          "Mailboxes"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:read",
        "parameters": [
          {
            "name": "domainId",
            "in": "query",
            "required": false,
            "description": "Only mailboxes on this domain.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "mailboxes": [
                    {
                      "id": "7854885b-10e0-4dee-a7df-88351b9ae155",
                      "address": "docs.example@northwind-local.test",
                      "display_name": "API docs example",
                      "quota_mb": 10240,
                      "state": "active",
                      "used_bytes": null,
                      "message_count": null,
                      "usage_at": null,
                      "state_reason": null,
                      "created_at": "2026-10-30T06:16:53.907Z",
                      "domain": "northwind-local.test",
                      "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                      "mail_host": "mail.rykontech.com",
                      "webmail_url": "https://mail.rykonmail.com/",
                      "agent_id": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "post": {
        "operationId": "mailboxes.create",
        "summary": "Create a mailbox",
        "description": "Creates a mailbox and answers 202 while it is made. It has no password until you issue one with POST /mailboxes/:id/password. The domain must be verified and its sending set up (409 until then, usually a minute or two after verifying). An address that exists answers 409, as does a quota above your plan's largest mailbox or a plan with no room for another. Needs mailboxes:write.",
        "tags": [
          "Mailboxes"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domainId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The domain it is on."
                  },
                  "localPart": {
                    "type": "string",
                    "description": "The part before the @, up to 64 characters."
                  },
                  "displayName": {
                    "type": "string",
                    "description": "Up to 200 characters."
                  },
                  "quotaMb": {
                    "type": "integer",
                    "description": "Size in MB, 64 or more; your plan's default if left out."
                  }
                },
                "required": [
                  "domainId",
                  "localPart"
                ]
              },
              "example": {
                "domainId": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                "localPart": "docs.example",
                "displayName": "API docs example"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "7854885b-10e0-4dee-a7df-88351b9ae155",
                  "address": "docs.example@northwind-local.test",
                  "state": "requested",
                  "job": {
                    "id": "493ab353-4e03-4b77-b451-a006ac0b2903"
                  },
                  "next": "The mailbox is being created. It has no password until one is issued through POST /v1/mailboxes/:id/password."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/mailboxes/{id}/password": {
      "post": {
        "operationId": "mailboxes.password",
        "summary": "Set a new mailbox password",
        "description": "Issues a new password and returns it in this response only: it is never stored and cannot be read back, so a lost one is replaced, not recovered. The old password stops working. Only an active mailbox can have one (409), and an agent's mailbox is managed through its agent (409). Needs mailboxes:write.",
        "tags": [
          "Mailboxes"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The mailbox's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "address": "docs.example@northwind-local.test",
                  "password": "w3we...",
                  "shownOnce": "This password is shown once and is not stored. Issue a new one if it is lost."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/mailboxes/{id}": {
      "delete": {
        "operationId": "mailboxes.delete",
        "summary": "Delete a mailbox",
        "description": "Deletes a mailbox and every message in it. Because that cannot be undone, the body must name the address in confirm (400 if it is missing, 409 if it does not match). A mailbox that belongs to an agent, or that a shared address delivers to, answers 409 until that is changed. Needs mailboxes:write.",
        "tags": [
          "Mailboxes"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The mailbox's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm": {
                    "type": "string",
                    "description": "The mailbox's address, typed out."
                  }
                },
                "required": [
                  "confirm"
                ]
              },
              "example": {
                "confirm": "docs.example@northwind-local.test"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "removed": true,
                  "address": "docs.example@northwind-local.test"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/aliases": {
      "get": {
        "operationId": "aliases.list",
        "summary": "List shared addresses",
        "description": "The account's shared addresses, by address, with the mailboxes each delivers to. Needs mailboxes:read.",
        "tags": [
          "Aliases"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:read",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "aliases": [
                    {
                      "id": "b9af2939-fc53-43cc-821b-07b180fae413",
                      "address": "docs-sales@northwind-local.test",
                      "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                      "created_at": "2026-10-30T06:17:15.298Z",
                      "targets": [
                        {
                          "id": "7854885b-10e0-4dee-a7df-88351b9ae155",
                          "address": "docs.example@northwind-local.test",
                          "name": "API docs example"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "post": {
        "operationId": "aliases.create",
        "summary": "Create a shared address",
        "description": "Makes an address like sales@ that delivers to one or more of your own mailboxes, an agent's included. Only your own active mailboxes can receive (400 otherwise); forwarding outside the account is not offered. The domain must be verified (409). An address that is already a mailbox or a shared address answers 409, as does a plan with no room for another. Needs mailboxes:write.",
        "tags": [
          "Aliases"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domainId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The domain it is on."
                  },
                  "localPart": {
                    "type": "string",
                    "description": "The part before the @, up to 64 characters."
                  },
                  "targets": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "1 to 50 ids of active mailboxes on the account."
                  }
                },
                "required": [
                  "domainId",
                  "localPart",
                  "targets"
                ]
              },
              "example": {
                "domainId": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                "localPart": "docs-sales",
                "targets": [
                  "7854885b-10e0-4dee-a7df-88351b9ae155",
                  "14c2cc36-e349-419b-9bf6-4193fed78d1d"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "b9af2939-fc53-43cc-821b-07b180fae413",
                  "address": "docs-sales@northwind-local.test",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "created_at": "2026-10-30T06:17:15.298Z",
                  "targets": [
                    {
                      "id": "14c2cc36-e349-419b-9bf6-4193fed78d1d",
                      "address": "docs.agent@northwind-local.test",
                      "name": "API docs example"
                    },
                    {
                      "id": "7854885b-10e0-4dee-a7df-88351b9ae155",
                      "address": "docs.example@northwind-local.test",
                      "name": "API docs example"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/aliases/{id}": {
      "put": {
        "operationId": "aliases.update",
        "summary": "Change where a shared address delivers",
        "description": "Replaces the mailboxes a shared address delivers to. Only your own active mailboxes can receive (400 otherwise). Needs mailboxes:write.",
        "tags": [
          "Aliases"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The shared address's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "targets": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "1 to 50 ids of active mailboxes on the account."
                  }
                },
                "required": [
                  "targets"
                ]
              },
              "example": {
                "targets": [
                  "7854885b-10e0-4dee-a7df-88351b9ae155"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "b9af2939-fc53-43cc-821b-07b180fae413",
                  "address": "docs-sales@northwind-local.test",
                  "domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                  "created_at": "2026-10-30T06:17:15.298Z",
                  "targets": [
                    {
                      "id": "7854885b-10e0-4dee-a7df-88351b9ae155",
                      "address": "docs.example@northwind-local.test",
                      "name": "API docs example"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "delete": {
        "operationId": "aliases.delete",
        "summary": "Delete a shared address",
        "description": "Deletes a shared address; mail to it is no longer delivered. The mailboxes it delivered to are not touched. Needs mailboxes:write.",
        "tags": [
          "Aliases"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The shared address's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/agents": {
      "get": {
        "operationId": "agents.list",
        "summary": "List agents",
        "description": "The account's AI agents with their mailbox, what they may send and to whom, and what they did in the last 24 hours. Needs mailboxes:read.",
        "tags": [
          "AI agents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:read",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "agents": [
                    {
                      "id": "8ca997e9-6ff5-49bc-ba30-a0933f00012a",
                      "name": "API docs example",
                      "state": "active",
                      "address": "docs.agent@northwind-local.test",
                      "send_to": "listed",
                      "allow_list": [
                        "example.com"
                      ],
                      "daily_limit": 20,
                      "approve_all": true,
                      "created_at": "2026-10-30T06:16:53.930Z",
                      "on_new_mail": "nothing",
                      "notify_url": null,
                      "notify_secret_set": false,
                      "reply_instructions": "",
                      "watched_at": null,
                      "today": {
                        "agent_id": "8ca997e9-6ff5-49bc-ba30-a0933f00012a",
                        "sent": 1,
                        "read": 0,
                        "pending": 0
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "post": {
        "operationId": "agents.create",
        "summary": "Create an agent",
        "description": "Gives an AI agent a mailbox of its own and answers while it is set up (state \"provisioning\"). Its mailbox counts against your plan. The domain must be verified and its sending set up (409 until then), and an address that exists answers 409. By default it may write only to people who wrote to it first, 50 a day; change that with PUT /agents/:id. Needs mailboxes:write.",
        "tags": [
          "AI agents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1 to 80 characters; also the mailbox's display name."
                  },
                  "domainId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The domain its mailbox is on."
                  },
                  "localPart": {
                    "type": "string",
                    "description": "The part before the @, up to 64 characters."
                  }
                },
                "required": [
                  "name",
                  "domainId",
                  "localPart"
                ]
              },
              "example": {
                "name": "API docs example",
                "domainId": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
                "localPart": "docs.agent"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "8ca997e9-6ff5-49bc-ba30-a0933f00012a",
                  "name": "API docs example",
                  "state": "provisioning",
                  "address": "docs.agent@northwind-local.test",
                  "send_to": "repliers",
                  "allow_list": [],
                  "daily_limit": 50,
                  "approve_all": false,
                  "created_at": "2026-10-30T06:16:53.930Z",
                  "on_new_mail": "nothing",
                  "notify_url": null,
                  "notify_secret_set": false,
                  "reply_instructions": "",
                  "watched_at": null,
                  "keys": [],
                  "today": {
                    "agent_id": "8ca997e9-6ff5-49bc-ba30-a0933f00012a",
                    "sent": 0,
                    "read": 0,
                    "pending": 0
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/agents/approvals": {
      "get": {
        "operationId": "agents.approvals",
        "summary": "List messages waiting for approval",
        "description": "Every message an agent wrote that waits for a person, across the account, oldest first, with why it was held. Needs mailboxes:read.",
        "tags": [
          "AI agents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:read",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "waiting": [
                    {
                      "id": "9d60d5d5-5d40-4556-98d5-cf44f59c3a31",
                      "agent_id": "8ca997e9-6ff5-49bc-ba30-a0933f00012a",
                      "agent": "API docs example",
                      "agent_address": "docs.agent@northwind-local.test",
                      "recipients": [
                        "sam.lee@example.com"
                      ],
                      "cc": [],
                      "subject": "Your order 1",
                      "body": "Hi Sam,\n\nYour order is ready to collect from Friday.\n\nAPI docs example",
                      "held_because": "every message from this agent waits for a person",
                      "error": null,
                      "created_at": "2026-10-30T06:17:35.433Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/agents/outbox/{outboxId}/approve": {
      "post": {
        "operationId": "agents.approve",
        "summary": "Approve a held message",
        "description": "Sends a held message, as the agent wrote it or with your edits to the subject and body. Sent once however many times this is called: a message already decided answers 404, and one from a paused agent answers 409 and stays waiting. Answers whether it was sent. Needs mailboxes:write.",
        "tags": [
          "AI agents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "parameters": [
          {
            "name": "outboxId",
            "in": "path",
            "required": true,
            "description": "The held message's id, from GET /agents/approvals.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "subject": {
                    "type": "string",
                    "description": "A new subject, 1 to 300 characters."
                  },
                  "body": {
                    "type": "string",
                    "description": "A new body, up to 100,000 characters."
                  }
                }
              },
              "example": {
                "subject": "Your order is ready",
                "body": "Hi Sam,\n\nYour order is ready to collect from Friday, 9 to 5.\n\nNorthwind Traders"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "state": "sent",
                  "messageId": "<f7101765-c6c1-4999-9042-6fb8501a6ed8@northwind-local.test>"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/agents/outbox/{outboxId}/reject": {
      "post": {
        "operationId": "agents.reject",
        "summary": "Reject a held message",
        "description": "Rejects a held message, which is then never sent; the reason is kept in the agent's record. A message already decided answers 404. Needs mailboxes:write.",
        "tags": [
          "AI agents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "parameters": [
          {
            "name": "outboxId",
            "in": "path",
            "required": true,
            "description": "The held message's id, from GET /agents/approvals.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "Why, up to 500 characters."
                  }
                }
              },
              "example": {
                "reason": "Sent the first one already."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "state": "rejected"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/agents/{id}": {
      "get": {
        "operationId": "agents.get",
        "summary": "Get an agent",
        "description": "One agent, with its sending rules, its keys (never their secrets) and what it did in the last 24 hours. Needs mailboxes:read.",
        "tags": [
          "AI agents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The agent's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "8ca997e9-6ff5-49bc-ba30-a0933f00012a",
                  "name": "API docs example",
                  "state": "active",
                  "address": "docs.agent@northwind-local.test",
                  "send_to": "listed",
                  "allow_list": [
                    "example.com"
                  ],
                  "daily_limit": 20,
                  "approve_all": true,
                  "created_at": "2026-10-30T06:16:53.930Z",
                  "on_new_mail": "nothing",
                  "notify_url": null,
                  "notify_secret_set": false,
                  "reply_instructions": "",
                  "watched_at": null,
                  "keys": [
                    {
                      "id": "49b887b6-3473-4d17-b39c-1cc56283ea4b",
                      "prefix": "eqrf9c76cx0hy",
                      "name": "API docs capture",
                      "created_at": "2026-10-30T06:17:26.696Z",
                      "created_by": "key sa1pteyz44qbm",
                      "last_used_at": "2026-10-30T06:17:35.452Z"
                    }
                  ],
                  "today": {
                    "agent_id": "8ca997e9-6ff5-49bc-ba30-a0933f00012a",
                    "sent": 1,
                    "read": 0,
                    "pending": 0
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "put": {
        "operationId": "agents.update",
        "summary": "Set an agent's sending rules",
        "description": "Decides what an agent may send without a person: always to colleagues at its own domain, then to anyone, only people who wrote to it first, or an allow list, within a daily limit; with approveAll everything waits for a person. Send every field. Needs mailboxes:write.",
        "tags": [
          "AI agents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The agent's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1 to 80 characters."
                  },
                  "sendTo": {
                    "type": "string",
                    "enum": [
                      "anyone",
                      "repliers",
                      "listed"
                    ],
                    "description": "Who it may write to without approval."
                  },
                  "allowList": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 200 addresses or domains, for \"listed\"."
                  },
                  "dailyLimit": {
                    "type": "integer",
                    "description": "0 to 10,000 messages a day."
                  },
                  "approveAll": {
                    "type": "boolean",
                    "description": "Hold every message for a person."
                  }
                },
                "required": [
                  "name",
                  "sendTo",
                  "allowList",
                  "dailyLimit",
                  "approveAll"
                ]
              },
              "example": {
                "name": "API docs example",
                "sendTo": "listed",
                "allowList": [
                  "example.com"
                ],
                "dailyLimit": 20,
                "approveAll": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "id": "8ca997e9-6ff5-49bc-ba30-a0933f00012a",
                  "name": "API docs example",
                  "state": "active",
                  "address": "docs.agent@northwind-local.test",
                  "send_to": "listed",
                  "allow_list": [
                    "example.com"
                  ],
                  "daily_limit": 20,
                  "approve_all": true,
                  "created_at": "2026-10-30T06:16:53.930Z",
                  "on_new_mail": "nothing",
                  "notify_url": null,
                  "notify_secret_set": false,
                  "reply_instructions": "",
                  "watched_at": null,
                  "keys": [],
                  "today": {
                    "agent_id": "8ca997e9-6ff5-49bc-ba30-a0933f00012a",
                    "sent": 0,
                    "read": 0,
                    "pending": 0
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "delete": {
        "operationId": "agents.delete",
        "summary": "Remove an agent",
        "description": "Removes an AI agent. Its keys are revoked at once, every message it has waiting for approval is rejected, and its mailbox and every message in it are deleted. Because that cannot be undone, the body must name the agent's address in confirm (400 if it is missing, 409 if it does not match). In the console only the owner or an admin may remove an agent. Needs mailboxes:write.",
        "tags": [
          "AI agents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "mailboxes:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The agent's id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm": {
                    "type": "string",
                    "description": "The agent's address, typed out."
                  }
                },
                "required": [
                  "confirm"
                ]
              },
              "example": {
                "confirm": "helper@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "removed": true,
                  "address": "helper@example.com"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "rmk_live_...",
        "description": "An API key made in the console under Developers. Scopes: domains:read (Read your domains and the DNS records that set them up.); domains:write (Add domains and ask for their records to be checked.); mailboxes:read (Read mailboxes, aliases and AI agents, and the agent messages waiting for approval.); mailboxes:write (Create and delete mailboxes and aliases, reset passwords, set up agents, and approve or reject what they send.); audience:read (Read contacts, topics, forms, campaigns with their reports, and automations.); audience:write (Add, import and change contacts, and create, test and schedule campaigns, forms, topics and automations.); sending:read (Read the transactional email log.); mail:send (Send transactional email.)"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A stable code: bad_request, unauthorized, forbidden, not_found, conflict, refused, payment_required, rate_limited and so on."
          },
          "message": {
            "type": "string",
            "description": "A sentence for a person, saying what to change."
          }
        }
      }
    },
    "responses": {
      "E400": {
        "description": "The request is not valid; the message says which field and why.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E401": {
        "description": "No key, or a key that is not valid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E403": {
        "description": "The key does not hold the scope this operation needs; the message names it.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E404": {
        "description": "Not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E409": {
        "description": "A conflict, or a guard refused the request. Do not retry it unchanged.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E429": {
        "description": "Too many requests; wait for the seconds in retry-after.",
        "headers": {
          "retry-after": {
            "description": "Seconds to wait before trying again.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}