{
  "openapi": "3.0.3",
  "info": {
    "title": "bluefox.email Public API",
    "version": "1.0.0",
    "description": "The bluefox.email public REST API - create and manage projects' campaigns, transactional and triggered emails, templates, segments, subscriber lists, contacts, domains, sender identities, and more.\n\nEvery project-scoped endpoint is authenticated with a project API key, sent as a bearer token: `Authorization: Bearer YOUR_API_KEY`. Keys are managed in the app under Project Settings > API Keys - not exposed via this API.\n\nAll responses are wrapped as `{ \"status\": <http status>, \"result\": ... }` on success, or `{ \"status\": <http status>, \"error\": { \"name\": ..., \"message\": ... } }` on failure.\n\nList endpoints are paginated (`limit`, default 10, max 30; `skip`) and return `count` (total matching items) and `next` (the full URL of the next page, or null on the last page).\n\nNew projects start in sandbox status, which is rate-limited (a low daily send cap, plus automatic restriction on high bounce/complaint rates) - see the status field on the Project schema before assuming a send failure is a bug. Domain/sender-identity setup (see below) is available in sandbox too, but does not by itself lift the sandbox rate limit - that requires leaving sandbox status via the Production Access request flow (see below). To add a domain: POST /v1/projectId/{projectId}/domains, have its owner add the returned DNS records, re-check it (POST .../domains/{domainId}/check) until it verifies, then either use the sender identity that creates automatically or add another one for that domain (POST .../sender-identities). Not available for byoAwsSes projects, which manage domains directly in their own AWS account instead (see the BYO AWS endpoints).\n\nA note for AI agents specifically: when a user asks you to create or update something and leaves out a field that references another resource by ID (subscriberListId, segmentId, senderIdentity, doubleOptIn.emailId, etc.), do not ask the user for a raw ID and do not guess one. Call the relevant list endpoint first (e.g. GET /v1/projectId/{projectId}/subscriber-lists), show the user the real options, and let them choose by name - individual fields below flag exactly which list endpoint to use for this. Likewise, if the user leaves out an optional-but-meaningful field like previewText, ask what they want it to say rather than silently leaving it blank. Treat missing required fields the same way, proactively, rather than only reacting to the 400 error you get back if you skip straight to calling the endpoint.",
    "contact": {
      "name": "bluefox.email support",
      "url": "https://bluefox.email"
    }
  },
  "servers": [
    {
      "url": "https://api.bluefox.email",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Project"
    },
    {
      "name": "Design Systems"
    },
    {
      "name": "Domains"
    },
    {
      "name": "Sender Identities"
    },
    {
      "name": "Webhook"
    },
    {
      "name": "Contacts"
    },
    {
      "name": "Campaigns"
    },
    {
      "name": "Transactional Emails"
    },
    {
      "name": "Triggered Emails"
    },
    {
      "name": "Templates"
    },
    {
      "name": "Segments"
    },
    {
      "name": "Subscriber Lists"
    },
    {
      "name": "Suppression List"
    },
    {
      "name": "Test Email"
    },
    {
      "name": "Send Email"
    },
    {
      "name": "Subscriptions"
    },
    {
      "name": "Production Access"
    },
    {
      "name": "Sending Setup"
    },
    {
      "name": "BYO AWS"
    },
    {
      "name": "Email Error Log"
    },
    {
      "name": "Signup Forms"
    }
  ],
  "paths": {
    "/v1/projectId/{projectId}": {
      "get": {
        "tags": [
          "Project"
        ],
        "summary": "Get project settings",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Project"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "patch": {
        "tags": [
          "Project"
        ],
        "summary": "Update project settings",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Project"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/design-systems": {
      "get": {
        "tags": [
          "Design Systems"
        ],
        "summary": "List the project's design system (merged with its overrides)",
        "description": "Always a single-item list (or empty) - the design system this project is currently using (project.designSystemId), merged with the project's overrides (designSystemParams). Kept as a list for consistency with other resources.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "updatedAt",
                "createdAt"
              ],
              "default": "updatedAt"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DesignSystem"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/design-systems/{id}": {
      "patch": {
        "tags": [
          "Design Systems"
        ],
        "summary": "Set or reset design system overrides for this project",
        "description": "Batch operation: setOverrides upserts one or more variable/font/component overrides by name, resetOverrides removes them (falling back to the base design system value). id must be the project's own design system (project.designSystemId) - this endpoint cannot be used to switch a project to a different design system, even one belonging to the same account.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The design system _id - must equal project.designSystemId."
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DesignSystemPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/DesignSystem"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Design system not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Design system not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/domains": {
      "get": {
        "tags": [
          "Domains"
        ],
        "summary": "List sending domains",
        "description": "Not paginated - always returns every domain on the project (there are only ever a handful). Supports filter[<field>]=value exact-match filtering (e.g. filter[domain]=example.com) to look one up directly instead of scanning the full list.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[domain]=example.com or filter[region]=eu-north-1. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Domain"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Domains"
        ],
        "summary": "Add a sending domain",
        "description": "Production-access projects only. Returns the required DNS records to add before the domain can send.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DomainInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Domain"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/domains/{domainId}": {
      "get": {
        "tags": [
          "Domains"
        ],
        "summary": "Get a single domain",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Domain"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Domain not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Domain not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Domains"
        ],
        "summary": "Remove a domain",
        "description": "Fails while a sender identity still uses this domain/region.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "_id": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Domain not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Domain not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/domains/{domainId}/check": {
      "post": {
        "tags": [
          "Domains"
        ],
        "summary": "Re-check DNS verification status for a domain",
        "description": "Re-reads the DKIM/SPF/MX/DMARC DNS records for the domain. Auto-creates a default sender identity (no-reply@domain) the first time verification succeeds.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Domain"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Domain not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Domain not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/sender-identities": {
      "get": {
        "tags": [
          "Sender Identities"
        ],
        "summary": "List sender identities",
        "description": "There is no separate \"default\" flag - the first item in the returned list is the default sender identity (used when an email doesn't specify one). Use POST .../set-default to change which one is first. Not paginated - always returns every identity on the project. Supports filter[<field>]=value exact-match filtering (e.g. filter[email]=support@example.com) to look one up directly instead of scanning the full list.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[email]=support@example.com. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SenderIdentity"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Sender Identities"
        ],
        "summary": "Add a sender identity",
        "description": "The email's domain must be a verified domain on this project, in the given region.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SenderIdentityInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SenderIdentity"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/sender-identities/{identityId}/set-default": {
      "post": {
        "tags": [
          "Sender Identities"
        ],
        "summary": "Set a sender identity as the default",
        "description": "Moves this identity to the front of the sender identities list - the position that determines which one is used by default.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "identityId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SenderIdentity"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Sender identity not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Sender identity not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/sender-identities/{identityId}": {
      "delete": {
        "tags": [
          "Sender Identities"
        ],
        "summary": "Delete a sender identity",
        "description": "Fails while a campaign, transactional email, triggered email, or automation email still uses it.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "identityId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "_id": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Sender identity not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Sender identity not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/webhook": {
      "get": {
        "tags": [
          "Webhook"
        ],
        "summary": "Get the configured webhook",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "responses": {
          "200": {
            "description": "OK, result is null if no webhook is configured",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "patch": {
        "tags": [
          "Webhook"
        ],
        "summary": "Create or replace the webhook configuration",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "delete": {
        "tags": [
          "Webhook"
        ],
        "summary": "Remove the webhook configuration",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Webhook not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/contacts/fields": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "List custom contact fields",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ContactField"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Create a custom contact field",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactField"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/ContactField"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/contacts/fields/{name}": {
      "delete": {
        "tags": [
          "Contacts"
        ],
        "summary": "Delete a custom contact field",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Custom contact field not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Custom contact field not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/contacts": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "List contacts",
        "description": "Accepts an API key or a whitelisted Origin header.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "object"
            },
            "description": "mongoose-crudl style filter object."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Contact"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Create a contact",
        "description": "Accepts an API key or a whitelisted Origin header (for client-side widget use).",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Contact"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/contacts/{email}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get a contact by email",
        "description": "Accepts an API key or a whitelisted Origin header.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Contact"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contact not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contact not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Contacts"
        ],
        "summary": "Update a contact",
        "description": "Accepts an API key or a whitelisted Origin header.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Contact"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contact not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contact not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      },
      "delete": {
        "tags": [
          "Contacts"
        ],
        "summary": "Delete a contact",
        "description": "Also removes the contact from every subscriber list. Accepts an API key or a whitelisted Origin header.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Contact"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contact not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contact not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/contacts/{projectId}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "List contacts (legacy flat URL shape)",
        "description": "Legacy flat URL shape, kept for backward compatibility - identical behavior to GET /v1/projectId/{projectId}/contacts above.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "object"
            },
            "description": "mongoose-crudl style filter object."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Contact"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Create a contact (legacy flat URL shape)",
        "description": "Legacy flat URL shape, kept for backward compatibility - identical behavior to POST /v1/projectId/{projectId}/contacts above. Accepts an API key or a whitelisted Origin header (for client-side widget use).",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Contact"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/contacts/{projectId}/{email}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get a contact by email (legacy flat URL shape)",
        "description": "Legacy flat URL shape, kept for backward compatibility - identical behavior to GET /v1/projectId/{projectId}/contacts/{email} above.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Contact"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contact not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contact not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Contacts"
        ],
        "summary": "Update a contact (legacy flat URL shape)",
        "description": "Legacy flat URL shape, kept for backward compatibility - identical behavior to PATCH /v1/projectId/{projectId}/contacts/{email} above. Accepts an API key or a whitelisted Origin header.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Contact"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contact not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contact not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      },
      "delete": {
        "tags": [
          "Contacts"
        ],
        "summary": "Delete a contact (legacy flat URL shape)",
        "description": "Legacy flat URL shape, kept for backward compatibility - identical behavior to DELETE /v1/projectId/{projectId}/contacts/{email} above.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Contact"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contact not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contact not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/test-email/{id}": {
      "post": {
        "tags": [
          "Test Email"
        ],
        "summary": "Send a test email",
        "description": "Sends a campaign, triggered, or transactional email to a single recipient (by email or by picking a contact from a private subscriber list) without affecting real send stats or contact state.\n\nSending fails with a 405 if the account is out of email credit (\"Insufficient credits available\") - there is no public endpoint to check remaining balance ahead of time, only in the app. It also fails with a 405 if a sandbox project's daily send cap is exceeded, or if bounce/complaint rates have triggered automatic restriction (see Project.status and GET .../sandbox/deliverability).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The campaign/triggered-email/transactional-email _id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "campaign",
                      "triggered",
                      "transactional"
                    ]
                  },
                  "email": {
                    "type": "string",
                    "description": "Required unless subscriberListId is given."
                  },
                  "subscriberListId": {
                    "type": "string",
                    "description": "A private subscriber list to send to (picks a subscriber from it). Required unless email is given."
                  },
                  "data": {
                    "description": "Template variables to render into the email."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK, queued for sending",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/send-transactional": {
      "post": {
        "tags": [
          "Send Email"
        ],
        "summary": "Send a transactional email",
        "description": "The project is resolved from transactionalId, not just the URL - the URL's projectId must match the transactional email's own project, or this 404s.\n\nSending fails with a 405 if the account is out of email credit (\"Insufficient credits available\") - there is no public endpoint to check remaining balance ahead of time, only in the app. It also fails with a 405 if a sandbox project's daily send cap is exceeded, or if bounce/complaint rates have triggered automatic restriction (see Project.status and GET .../sandbox/deliverability).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "transactionalId"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "transactionalId": {
                    "type": "string",
                    "description": "A transactional email _id, from GET /v1/projectId/{projectId}/transactional-emails - NOT a template ID."
                  },
                  "data": {
                    "description": "Template variables to render into the email."
                  },
                  "attachments": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "filename": {
                          "type": "string"
                        },
                        "content": {
                          "type": "string",
                          "description": "Base64-encoded file content."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK, queued for sending",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Transactional email not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Transactional email not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/send-triggered": {
      "post": {
        "tags": [
          "Send Email"
        ],
        "summary": "Send a triggered email",
        "description": "The project is resolved from triggeredId, not just the URL - the URL's projectId must match the triggered email's own project, or this 404s.\n\nSending fails with a 405 if the account is out of email credit (\"Insufficient credits available\") - there is no public endpoint to check remaining balance ahead of time, only in the app. It also fails with a 405 if a sandbox project's daily send cap is exceeded, or if bounce/complaint rates have triggered automatic restriction (see Project.status and GET .../sandbox/deliverability).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "triggeredId"
                ],
                "properties": {
                  "triggeredId": {
                    "type": "string",
                    "description": "A triggered email _id, from GET /v1/projectId/{projectId}/triggered-emails - NOT a template ID."
                  },
                  "emails": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Defaults to every active subscriber on the triggered email's subscriber list when omitted."
                  },
                  "data": {
                    "description": "Template variables to render into the email."
                  },
                  "attachments": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "filename": {
                          "type": "string"
                        },
                        "content": {
                          "type": "string",
                          "description": "Base64-encoded file content."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK, queued for sending",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Triggered email not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Triggered email not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/send-transactional": {
      "post": {
        "tags": [
          "Send Email"
        ],
        "summary": "Send a transactional email (legacy flat URL shape)",
        "description": "Legacy flat URL shape, kept for backward compatibility - identical behavior to POST /v1/projectId/{projectId}/send-transactional above (which is the same handler; there is no projectId in this URL because the project is resolved entirely from transactionalId).\n\nSending fails with a 405 if the account is out of email credit (\"Insufficient credits available\") - there is no public endpoint to check remaining balance ahead of time, only in the app. It also fails with a 405 if a sandbox project's daily send cap is exceeded, or if bounce/complaint rates have triggered automatic restriction (see Project.status and GET .../sandbox/deliverability).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "transactionalId"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "transactionalId": {
                    "type": "string",
                    "description": "A transactional email _id, from GET /v1/projectId/{projectId}/transactional-emails - NOT a template ID."
                  },
                  "data": {
                    "description": "Template variables to render into the email."
                  },
                  "attachments": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "filename": {
                          "type": "string"
                        },
                        "content": {
                          "type": "string",
                          "description": "Base64-encoded file content."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK, queued for sending",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Transactional email not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Transactional email not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/send-triggered": {
      "post": {
        "tags": [
          "Send Email"
        ],
        "summary": "Send a triggered email (legacy flat URL shape)",
        "description": "Legacy flat URL shape, kept for backward compatibility - identical behavior to POST /v1/projectId/{projectId}/send-triggered above (which is the same handler; there is no projectId in this URL because the project is resolved entirely from triggeredId).\n\nSending fails with a 405 if the account is out of email credit (\"Insufficient credits available\") - there is no public endpoint to check remaining balance ahead of time, only in the app. It also fails with a 405 if a sandbox project's daily send cap is exceeded, or if bounce/complaint rates have triggered automatic restriction (see Project.status and GET .../sandbox/deliverability).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "triggeredId"
                ],
                "properties": {
                  "triggeredId": {
                    "type": "string",
                    "description": "A triggered email _id, from GET /v1/projectId/{projectId}/triggered-emails - NOT a template ID."
                  },
                  "emails": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Defaults to every active subscriber on the triggered email's subscriber list when omitted."
                  },
                  "data": {
                    "description": "Template variables to render into the email."
                  },
                  "attachments": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "filename": {
                          "type": "string"
                        },
                        "content": {
                          "type": "string",
                          "description": "Base64-encoded file content."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK, queued for sending",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Triggered email not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Triggered email not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/subscriber-lists/{id}": {
      "get": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "List subscribers of a list",
        "description": "Legacy flat URL shape. Auth: API key (Authorization: Bearer) matching the list's project, OR an admin/account-owner JWT.\nUnlike GET /v1/projectId/{projectId}/contacts (where custom field values are flat top-level keys), here they are \nreturned nested under a \"customFields\" object, e.g. `{ \"email\": \"x@y.com\", \"customFields\": { \"plan\": \"pro\" } }`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "email": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "unverified",
                                  "active",
                                  "unsubscribed",
                                  "paused"
                                ]
                              },
                              "customFields": {
                                "type": "object",
                                "additionalProperties": true,
                                "description": "Custom contact field values, keyed by field name."
                              }
                            },
                            "additionalProperties": true
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "Subscribe a contact to a list",
        "description": "Legacy flat URL shape. Creates the contact if it doesn't exist yet. Triggers double opt-in if enabled on the list. Auth: API key, or a whitelisted Origin (in which case a CAPTCHA is required unless the list disables it).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "unverified",
                      "active"
                    ]
                  },
                  "captchaText": {
                    "type": "string"
                  },
                  "captchaProbe": {
                    "type": "string"
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/subscriber-lists/{id}/{email}": {
      "get": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "Get a subscriber by email",
        "description": "Legacy flat URL shape. Accepts an API key or a whitelisted Origin header.\nUnlike GET /v1/projectId/{projectId}/contacts/{email} (where custom field values are flat top-level keys), here they \nare returned nested under a \"customFields\" object, e.g. `{ \"email\": \"x@y.com\", \"customFields\": { \"plan\": \"pro\" } }`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "unverified",
                            "active",
                            "unsubscribed",
                            "paused"
                          ]
                        },
                        "customFields": {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "Custom contact field values, keyed by field name."
                        }
                      },
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "Update a subscriber (status, contact fields, pause/resubscribe)",
        "description": "Legacy flat URL shape. Setting status to \"paused\" requires pausedUntil (a future date). Accepts an API key or a whitelisted Origin header.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "unsubscribed"
                    ]
                  },
                  "pausedUntil": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/subscriber-lists/{id}/{email}/unsubscribe": {
      "post": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "One-click unsubscribe",
        "description": "Legacy flat URL shape. Not API-key authenticated - requires a signed one-click-unsubscribe token (the ?token= query param from a dispatched email's List-Unsubscribe link).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/signup-forms/{id}": {
      "post": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "Submit a hosted/embedded signup form",
        "description": "Legacy flat URL shape. Not API-key authenticated - requires a whitelisted Origin header, and (depending on the form config) a CAPTCHA. Subscribes the contact to every list configured on the form.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The signup form _id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "captchaText": {
                    "type": "string"
                  },
                  "captchaProbe": {
                    "type": "string"
                  },
                  "turnstileToken": {
                    "type": "string"
                  },
                  "termsAccepted": {
                    "type": "boolean"
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        },
                        "redirectTo": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/campaigns": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "List campaigns",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "createdAt",
                "updatedAt",
                "scheduledTo"
              ],
              "default": "name"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Campaign"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Create a campaign",
        "description": "subscriberListId and segmentId (if given) must belong to this same project - a valid ID from a different project 404s. Setting status \"scheduled\" with scheduledTo also requires the project to have usable sending credentials and enough account credit for the recipient count; missing either fails the whole create with a 400/405 rather than creating a draft.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Campaign"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/campaigns/{id}": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Get a single campaign",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Campaign"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Campaigns not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Campaigns not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Partially update a campaign",
        "description": "Merges the given fields into the existing document - omitted fields are left unchanged. Nothing is required (unlike create) since every field is optional on a partial update.\n\nsubscriberListId/segmentId are re-validated the same way as create. A campaign cannot be updated (including un-scheduling it) within 6 minutes of its scheduledTo time - it 400s with a message that says \"5 minutes\" but the actual cutoff is 6.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignInputPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Campaign"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Campaigns not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Campaigns not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Delete a campaign",
        "description": "Same 6-minute-before-send lock as PATCH applies to DELETE.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Campaign"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Campaigns not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Campaigns not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/transactional-emails": {
      "get": {
        "tags": [
          "Transactional Emails"
        ],
        "summary": "List transactional emails",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "createdAt",
                "updatedAt"
              ],
              "default": "name"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/TransactionalEmail"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Transactional Emails"
        ],
        "summary": "Create a transactional email",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionalEmailInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/TransactionalEmail"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/transactional-emails/{id}": {
      "get": {
        "tags": [
          "Transactional Emails"
        ],
        "summary": "Get a single transactional email",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/TransactionalEmail"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Transactional Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Transactional Emails not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Transactional Emails"
        ],
        "summary": "Partially update a transactional email",
        "description": "Merges the given fields into the existing document - omitted fields are left unchanged. Nothing is required (unlike create) since every field is optional on a partial update.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionalEmailInputPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/TransactionalEmail"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Transactional Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Transactional Emails not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Transactional Emails"
        ],
        "summary": "Delete a transactional email",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/TransactionalEmail"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Transactional Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Transactional Emails not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/triggered-emails": {
      "get": {
        "tags": [
          "Triggered Emails"
        ],
        "summary": "List triggered emails",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "createdAt",
                "updatedAt"
              ],
              "default": "name"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/TriggeredEmail"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Triggered Emails"
        ],
        "summary": "Create a triggered email",
        "description": "subscriberListId must belong to this same project - a valid ID from a different project 404s.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TriggeredEmailInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/TriggeredEmail"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/triggered-emails/{id}": {
      "get": {
        "tags": [
          "Triggered Emails"
        ],
        "summary": "Get a single triggered email",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/TriggeredEmail"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Triggered Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Triggered Emails not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Triggered Emails"
        ],
        "summary": "Partially update a triggered email",
        "description": "Merges the given fields into the existing document - omitted fields are left unchanged. Nothing is required (unlike create) since every field is optional on a partial update.\n\nsubscriberListId is re-validated the same way as create.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TriggeredEmailInputPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/TriggeredEmail"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Triggered Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Triggered Emails not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Triggered Emails"
        ],
        "summary": "Delete a triggered email",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/TriggeredEmail"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Triggered Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Triggered Emails not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/templates": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "List templates",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "createdAt",
                "updatedAt"
              ],
              "default": "name"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Template"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Templates"
        ],
        "summary": "Create a template",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Template"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/templates/{id}": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Get a single template",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Template"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Templates not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Templates not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Templates"
        ],
        "summary": "Partially update a template",
        "description": "Merges the given fields into the existing document - omitted fields are left unchanged. Nothing is required (unlike create) since every field is optional on a partial update.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateInputPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Template"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Templates not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Templates not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Templates"
        ],
        "summary": "Delete a template",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Template"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Templates not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Templates not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/segments": {
      "get": {
        "tags": [
          "Segments"
        ],
        "summary": "List segments",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "createdAt",
                "updatedAt"
              ],
              "default": "name"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Segment"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Segments"
        ],
        "summary": "Create a segment",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SegmentInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Segment"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/segments/{id}": {
      "get": {
        "tags": [
          "Segments"
        ],
        "summary": "Get a single segment",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Segment"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Segments not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Segments not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Segments"
        ],
        "summary": "Partially update a segment",
        "description": "Merges the given fields into the existing document - omitted fields are left unchanged. Nothing is required (unlike create) since every field is optional on a partial update.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SegmentInputPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Segment"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Segments not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Segments not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Segments"
        ],
        "summary": "Delete a segment",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Segment"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Segments not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Segments not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/subscriber-lists": {
      "get": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "List subscriber lists",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "updatedAt",
                "createdAt"
              ],
              "default": "updatedAt"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SubscriberList"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "Create a subscriber list",
        "description": "doubleOptIn.emailId (if given) must be a transactional email belonging to this same project - a valid ID from a different project 404s. When doubleOptIn.active is true, that email's content must also include {{verifyLink}}.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriberListInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SubscriberList"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/subscriber-lists/{id}": {
      "get": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "Get a single subscriber list",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SubscriberList"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber Lists not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber Lists not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "Partially update a subscriber list",
        "description": "Merges the given fields into the existing document - omitted fields are left unchanged. Nothing is required (unlike create) since every field is optional on a partial update.\n\ndoubleOptIn.emailId and the {{verifyLink}} content requirement are re-validated the same way as create.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriberListInputPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SubscriberList"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber Lists not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber Lists not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "Delete a subscriber list",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SubscriberList"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber Lists not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber Lists not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/suppression-list": {
      "get": {
        "tags": [
          "Suppression List"
        ],
        "summary": "List suppression list",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "email",
                "createdAt"
              ],
              "default": "email"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SuppressionListEntry"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Suppression List"
        ],
        "summary": "Create a suppression list",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SuppressionListEntryInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SuppressionListEntry"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/contacts/tags": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "List contacts",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "value",
                "createdAt",
                "updatedAt"
              ],
              "default": "value"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ContactTag"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Create a contact",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactTagInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/ContactTag"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/contacts/tags/{id}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get a single contact",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/ContactTag"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contacts not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contacts not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Contacts"
        ],
        "summary": "Partially update a contact",
        "description": "Merges the given fields into the existing document - omitted fields are left unchanged. Nothing is required (unlike create) since every field is optional on a partial update.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactTagInputPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/ContactTag"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contacts not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contacts not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Contacts"
        ],
        "summary": "Delete a contact",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/ContactTag"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contacts not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contacts not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/signup-forms": {
      "get": {
        "tags": [
          "Signup Forms"
        ],
        "summary": "List signup forms",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "updatedAt",
                "createdAt"
              ],
              "default": "updatedAt"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SignUpForm"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Signup Forms"
        ],
        "summary": "Create a signup form",
        "description": "doubleOptIn.emailId (if given) must be a transactional email belonging to this same project - a valid ID from a different project 404s. When doubleOptIn.active is true, that email's content must also include {{verifyLink}}. See also GET .../signup-forms/{id}/embed for the ready-to-paste HTML.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignUpFormInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SignUpForm"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/signup-forms/{id}": {
      "get": {
        "tags": [
          "Signup Forms"
        ],
        "summary": "Get a single signup form",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SignUpForm"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Signup Forms not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Signup Forms not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Signup Forms"
        ],
        "summary": "Partially update a signup form",
        "description": "Merges the given fields into the existing document - omitted fields are left unchanged. Nothing is required (unlike create) since every field is optional on a partial update.\n\ndoubleOptIn.emailId and the {{verifyLink}} content requirement are re-validated the same way as create.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignUpFormInputPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SignUpForm"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Signup Forms not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Signup Forms not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Signup Forms"
        ],
        "summary": "Delete a signup form",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SignUpForm"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Signup Forms not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Signup Forms not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/campaigns/{id}/stats": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Get stats for a single campaign",
        "description": "Aggregate counts only, never a per-recipient list - response size and query cost are bounded regardless of how much activity actually happened, since every count is a single indexed query scoped to this one resource. For the actual list of recipients (who received/opened/clicked/bounced/unsubscribed), see GET /v1/projectId/{projectId}/campaigns/{id}/recipients.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The campaign _id."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only count events at or after this date/time."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only count events at or before this date/time. If both from and to are given, the range between them cannot exceed 366 days."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/EmailStats"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Campaigns not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Campaigns not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/transactional-emails/{id}/stats": {
      "get": {
        "tags": [
          "Transactional Emails"
        ],
        "summary": "Get stats for a single transactional email",
        "description": "Aggregate counts only, never a per-recipient list - response size and query cost are bounded regardless of how much activity actually happened, since every count is a single indexed query scoped to this one resource. For the actual list of recipients (who received/opened/clicked/bounced/unsubscribed), see GET /v1/projectId/{projectId}/transactional-emails/{id}/recipients.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The transactional email _id."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only count events at or after this date/time."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only count events at or before this date/time. If both from and to are given, the range between them cannot exceed 366 days."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/EmailStats"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Transactional Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Transactional Emails not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/triggered-emails/{id}/stats": {
      "get": {
        "tags": [
          "Triggered Emails"
        ],
        "summary": "Get stats for a single triggered email",
        "description": "Aggregate counts only, never a per-recipient list - response size and query cost are bounded regardless of how much activity actually happened, since every count is a single indexed query scoped to this one resource. For the actual list of recipients (who received/opened/clicked/bounced/unsubscribed), see GET /v1/projectId/{projectId}/triggered-emails/{id}/recipients.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The triggered email _id."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only count events at or after this date/time."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only count events at or before this date/time. If both from and to are given, the range between them cannot exceed 366 days."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/EmailStats"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Triggered Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Triggered Emails not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/subscriber-lists/{id}/stats": {
      "get": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "Get stats for a single subscriber list",
        "description": "Aggregate counts only, never a per-recipient list - response size and query cost are bounded regardless of how much activity actually happened, since every count is a single indexed query scoped to this one resource. For the actual list of recipients (who received/opened/clicked/bounced/unsubscribed), see GET /v1/projectId/{projectId}/subscriber-lists/{id}/recipients.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only count events at or after this date/time."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only count events at or before this date/time. If both from and to are given, the range between them cannot exceed 366 days."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SubscriberListStats"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber Lists not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber Lists not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/subscriber-lists/{id}/subscribers": {
      "get": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "List subscribers on a list, with their contact data",
        "description": "Project-scoped equivalent of GET /v1/subscriber-lists/{id} (which is a legacy flat URL shape kept for hosted signup \nforms and one-click-unsubscribe links). Each item merges the subscriber's per-list status with their contact data - \ncustom field values come back nested under a \"customFields\" object here, not flattened onto top-level keys like \nGET /v1/projectId/{projectId}/contacts.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "updatedAt",
                "createdAt"
              ],
              "default": "updatedAt"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "email": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "unverified",
                                  "active",
                                  "unsubscribed",
                                  "paused"
                                ]
                              },
                              "customFields": {
                                "type": "object",
                                "additionalProperties": true,
                                "description": "Custom contact field values, keyed by field name."
                              }
                            },
                            "additionalProperties": true
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber list not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber list not found."
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "Subscribe a contact to a list",
        "description": "Project-scoped equivalent of POST /v1/subscriber-lists/{id} (which is a legacy flat URL shape kept for hosted \nsignup forms - it also accepts a whitelisted Origin header and CAPTCHA, neither of which apply here since this \nroute is API-key only). Creates the contact if it doesn't exist yet. Triggers double opt-in if enabled on the \nlist, unless status is explicitly set to \"active\".",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "unverified",
                      "active"
                    ]
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "unverified",
                            "active",
                            "unsubscribed",
                            "paused"
                          ]
                        },
                        "customFields": {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "Custom contact field values, keyed by field name."
                        }
                      },
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber list not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber list not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/subscriber-lists/{id}/subscribers/{email}": {
      "get": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "Get a single subscriber's status and contact data on a list",
        "description": "Project-scoped equivalent of GET /v1/subscriber-lists/{id}/{email} (which is a legacy flat URL shape kept for hosted \nsignup forms and one-click-unsubscribe links). Custom field values come back nested under a \"customFields\" object \nhere, not flattened onto top-level keys like GET /v1/projectId/{projectId}/contacts/{email}.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "unverified",
                            "active",
                            "unsubscribed",
                            "paused"
                          ]
                        },
                        "customFields": {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "Custom contact field values, keyed by field name."
                        }
                      },
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "Update a subscriber (status, contact fields, pause/resubscribe)",
        "description": "Project-scoped equivalent of PATCH /v1/subscriber-lists/{id}/{email} (which is a legacy flat URL shape kept for \nhosted signup forms). Setting status to \"paused\" requires pausedUntil (a future date).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The subscriber list _id."
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "unsubscribed"
                    ]
                  },
                  "pausedUntil": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "unverified",
                            "active",
                            "unsubscribed",
                            "paused"
                          ]
                        },
                        "customFields": {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "Custom contact field values, keyed by field name."
                        }
                      },
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Subscriber not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Subscriber not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/campaigns/{id}/recipients": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "List recipients of a single campaign",
        "description": "One row per actual recipient - who received it, how many times they opened/clicked, and whether they bounced/complained/unsubscribed/paused/subscribed/resubscribed as a result of this specific send. Supports the usual filter[<field>] exact-match filtering (e.g. filter[unsubscribed]=true, filter[status]=failed), plus two convenience filters not tied to a literal field: filter[opened]=true/false and filter[clicked]=true/false.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The campaign _id."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sentAt",
                "createdAt",
                "email"
              ],
              "default": "sentAt"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DispatchedEmailRecipient"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Campaigns not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Campaigns not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/transactional-emails/{id}/recipients": {
      "get": {
        "tags": [
          "Transactional Emails"
        ],
        "summary": "List recipients of a single transactional email",
        "description": "One row per actual recipient - who received it, how many times they opened/clicked, and whether they bounced/complained/unsubscribed/paused/subscribed/resubscribed as a result of this specific send. Supports the usual filter[<field>] exact-match filtering (e.g. filter[unsubscribed]=true, filter[status]=failed), plus two convenience filters not tied to a literal field: filter[opened]=true/false and filter[clicked]=true/false.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The transactional email _id."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sentAt",
                "createdAt",
                "email"
              ],
              "default": "sentAt"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DispatchedEmailRecipient"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Transactional Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Transactional Emails not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/triggered-emails/{id}/recipients": {
      "get": {
        "tags": [
          "Triggered Emails"
        ],
        "summary": "List recipients of a single triggered email",
        "description": "One row per actual recipient - who received it, how many times they opened/clicked, and whether they bounced/complained/unsubscribed/paused/subscribed/resubscribed as a result of this specific send. Supports the usual filter[<field>] exact-match filtering (e.g. filter[unsubscribed]=true, filter[status]=failed), plus two convenience filters not tied to a literal field: filter[opened]=true/false and filter[clicked]=true/false.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The triggered email _id."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 30
            },
            "description": "Max items per page. Capped at 30."
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of items to skip, for pagination."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sentAt",
                "createdAt",
                "email"
              ],
              "default": "sentAt"
            },
            "description": "Field to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "filter[<field>]",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter on a top-level field, e.g. filter[name]=Welcome. Repeatable for multiple fields."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DispatchedEmailRecipient"
                          }
                        },
                        "count": {
                          "type": "integer",
                          "description": "Total matching items across all pages, not just this page."
                        },
                        "next": {
                          "type": "string",
                          "nullable": true,
                          "description": "Full URL (path + query string) of the next page, or null if this is the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Triggered Emails not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Triggered Emails not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/production-access": {
      "get": {
        "tags": [
          "Production Access"
        ],
        "summary": "Get production access status",
        "description": "Combined view of the project's production-access request status and domain verification readiness.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/ProductionAccessStatus"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      },
      "post": {
        "tags": [
          "Production Access"
        ],
        "summary": "Apply for production access",
        "description": "The standard way to move a project past sandbox limits while still sending through bluefox.email's shared infrastructure - no AWS account of its own required. (PATCH .../projectId/{projectId} awsConfig is the separate, less common path for a project that wants to send through its own AWS account instead.) Requires at least one domain with SPF, MX, and DKIM all verified (see the Domains endpoints) - resubmitting after a decline only requires DKIM to still be verified. Approval is manual and not part of this API.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductionAccessReqInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "_id": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "pending"
                          ]
                        }
                      },
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/production-access/limit-increase": {
      "post": {
        "tags": [
          "Production Access"
        ],
        "summary": "Request a sending-limit increase",
        "description": "Production projects only, and only once a production-access request already exists. Fails if a limit-increase is already pending.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LimitIncreaseInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/ProductionAccessStatus"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/regions": {
      "get": {
        "tags": [
          "Sending Setup"
        ],
        "summary": "List AWS regions available for production sending",
        "description": "The valid values for a domain's or sender identity's region field when adding one for a production (non-BYO) project.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "regions": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "example": [
                            "us-east-1",
                            "eu-north-1"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/aws-check": {
      "post": {
        "tags": [
          "BYO AWS"
        ],
        "summary": "Validate BYO-AWS credentials",
        "description": "Checks credentials directly against SES - confirms they work, every sender identity is actually verified in SES, and the requested limit is within the account's max send rate. Does not persist anything - pair with PATCH /v1/projectId/{projectId} to save. Only relevant for BYO-AWS projects; calling this with nothing stored and no override fields will fail since there is nothing to check - that is not itself a sign anything is misconfigured, most projects simply do not use BYO-AWS. Use GET .../production-access for a project on bluefox.email's shared infrastructure instead.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AwsCheckInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/cloudformation-link": {
      "get": {
        "tags": [
          "BYO AWS"
        ],
        "summary": "Get the BYO-AWS CloudFormation setup link",
        "description": "Generates (once, then reuses) the project's external ID and returns a CloudFormation quick-create link for the STS role bluefox.email needs to send through the project's own AWS account.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/CloudformationLink"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/sandbox/deliverability": {
      "get": {
        "tags": [
          "Sending Setup"
        ],
        "summary": "Get sandbox sending deliverability",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/SandboxDeliverability"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/production/deliverability": {
      "get": {
        "tags": [
          "Sending Setup"
        ],
        "summary": "Get production sending deliverability",
        "description": "Worst bounce/complaint rate over the last 7/30/90 days, a per-verified-domain breakdown, and this month's send count against the monthly limit.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/ProductionDeliverability"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/test-webhook": {
      "get": {
        "tags": [
          "Sending Setup"
        ],
        "summary": "Send a synthetic test webhook event",
        "description": "Fires a synthetic event of the given type at the project's configured webhook URL, to confirm it's reachable and correctly signed. 503 if the webhook endpoint itself rejects or errors on the test request.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "bounce",
                "complaint",
                "open",
                "click",
                "pause-subscription",
                "unsubscribe",
                "subscribe",
                "resubscribe",
                "sent",
                "failed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/TestWebhookResult"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/domains/{domainId}/export/csv": {
      "get": {
        "tags": [
          "Sending Setup"
        ],
        "summary": "Export a domain's required DNS records as CSV",
        "description": "Returns a raw CSV file (Content-Disposition attachment), not the usual {status, result} JSON envelope.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/subscriber-lists/{subscriberListId}/contacts/{email}/resend-verification-email": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Resend a double opt-in verification email",
        "description": "Only works while the contact is still \"unverified\" on the given list, and only when double opt-in is enabled (either on the list, or on the signup form they originally used).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "subscriberListId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contact not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Contact not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/related-to/{relatedToId}/email-error-logs": {
      "get": {
        "tags": [
          "Email Error Log"
        ],
        "summary": "List processing/delivery errors for an email",
        "description": "Merges send-processing errors and delivery failures from the last 30 days, newest first.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "relatedToId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The campaign/transactional/triggered email _id."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100
            }
          },
          {
            "name": "skip",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/EmailErrorLog"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/signup-forms/{id}/embed": {
      "get": {
        "tags": [
          "Signup Forms"
        ],
        "summary": "Get a signup form's embeddable HTML",
        "description": "Returns the same self-contained HTML (styling, markup, and captcha/submit JS included) shown on the dashboard's \"embed\" tab - ready to paste as-is into an external site. Returns a raw HTML file (Content-Disposition attachment), not the usual {status, result} JSON envelope.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "HTML file",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Signup form not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 404
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": 404,
                  "error": {
                    "name": "NOT_FOUND",
                    "message": "Signup form not found."
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A project API key, created and managed in the app under Project Settings > API Keys - not exposed via this API."
      }
    },
    "schemas": {
      "Campaign": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "archive",
              "sent",
              "scheduled",
              "being-sent",
              "error"
            ]
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string"
          },
          "timeZone": {
            "type": "string"
          },
          "subscriberListId": {
            "type": "string"
          },
          "segmentId": {
            "type": "string",
            "nullable": true
          },
          "scheduledTo": {
            "type": "string",
            "format": "date-time"
          },
          "senderIdentity": {
            "type": "string"
          },
          "replyTo": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "chamaileon",
              "html",
              "text"
            ]
          },
          "excludeUnengaged": {
            "type": "boolean"
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "url",
                "feedType",
                "variableName"
              ],
              "properties": {
                "url": {
                  "type": "string"
                },
                "feedType": {
                  "type": "string",
                  "enum": [
                    "rss-xml",
                    "json"
                  ],
                  "description": "\"rss-xml\" covers both RSS and Atom XML feeds - which one it actually is gets auto-detected from the feed content itself, which changes the array key inside the template (see variableName below)."
                },
                "variableName": {
                  "type": "string",
                  "description": "No spaces allowed. This becomes a top-level Handlebars variable in the document (see the `document` field on \nthe parent email for the templating syntax). The feed's parsed items are NOT directly at `{{variableName}}` - \nthey're nested under a feed-shape-dependent array key you loop over with the custom `each` helper:\n  - feedType \"rss-xml\" that turns out to be RSS: `{{#each <variableName>.item}}...{{/each}}` (array key is the literal word \"item\", singular)\n  - feedType \"rss-xml\" that turns out to be Atom: `{{#each <variableName>.entry}}...{{/each}}` (array key is \"entry\")\n  - feedType \"json\": the array key is whatever field the source JSON actually uses for its list (e.g. \"items\", \"articles\") - inspect the feed's JSON to find it, it is not fixed.\nInside the loop, each item's own fields are whatever the feed provides (e.g. RSS gives `{{this.title}}`, `{{this.link}}`, `{{this.pubDate}}`) - there is no fixed schema, it mirrors the feed's actual content one-to-one."
                },
                "maxItems": {
                  "type": "integer",
                  "default": 5,
                  "description": "Informational only - NOT enforced when the email is sent. To actually limit how many items render, pass limit (and optionally skip) as hash arguments on the each tag itself, e.g. `{{#each news.item limit=5 skip=0}}`."
                },
                "required": {
                  "type": "boolean",
                  "default": false
                },
                "availableFields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Informational only, for the app UI - not enforced or used when rendering."
                }
              }
            }
          },
          "errorMessage": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CampaignInput": {
        "type": "object",
        "required": [
          "name",
          "subject",
          "timeZone",
          "subscriberListId"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string",
            "description": "Optional, but meaningfully affects open rates - if the user hasn't given you one, ask what they'd like it to say rather than leaving it blank."
          },
          "timeZone": {
            "type": "string",
            "description": "IANA time zone, e.g. \"America/New_York\". Used to interpret scheduledTo."
          },
          "subscriberListId": {
            "type": "string",
            "description": "Required. If the user hasn't told you which list to send to, call GET /v1/projectId/{projectId}/subscriber-lists first and ask them to choose from the real list names - don't ask them for a raw ID."
          },
          "segmentId": {
            "type": "string",
            "description": "Optional - narrows the subscriberListId down further. If the user mentions targeting a specific segment by name but doesn't give an ID, call GET /v1/projectId/{projectId}/segments first and ask them to choose from the real names."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "archive",
              "scheduled"
            ],
            "description": "Set to \"scheduled\" together with scheduledTo to schedule sending."
          },
          "scheduledTo": {
            "type": "string",
            "format": "date-time"
          },
          "excludeUnengaged": {
            "type": "boolean"
          },
          "senderIdentity": {
            "type": "string",
            "description": "A sender identity _id. If the user hasn't told you which one to use, call GET /v1/projectId/{projectId}/sender-identities first and ask them to choose from the real email addresses returned - don't ask them for a raw ID."
          },
          "replyTo": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "html",
              "text"
            ],
            "description": "Omit to keep using the visual (Chamaileon) editor document. Set to \"html\" or \"text\" to author document as a raw Handlebars template string instead (see the document field)."
          },
          "document": {
            "description": "The email content. When type is omitted, this is opaque Chamaileon visual-editor JSON - not meant to be hand-authored. \nWhen type is \"html\" or \"text\", this is a plain string rendered with Handlebars at send time, and can use merge tags:\n  - `{{contact.email}}`, `{{contact.name}}`, and `{{contact.<yourCustomFieldName>}}` for any field from GET /v1/projectId/{projectId}/contacts/fields.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - Any feed's variableName (see the feeds field) as a loop, e.g. `{{#each news.item limit=5 skip=0}}...{{this.title}}...{{/each}}`.\n  - Standard `{{#if}}`/`{{#unless}}`, plus custom helpers AND, OR, NOT, EQ, INCLUDES, CAPITALIZE, TRUNCATE, DEFAULT, usable like `{{#if (EQ contact.plan \"pro\")}}...{{/if}}`.\nFor transactional/triggered sends, whatever object is passed as `data` on POST /v1/projectId/{projectId}/send-transactional or /v1/projectId/{projectId}/send-triggered is merged directly into the TOP LEVEL of the template context (not nested under a \"data\" key) - so sending `data: { \"orderId\": 123 }` makes `{{orderId}}` available, not `{{data.orderId}}`."
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "url",
                "feedType",
                "variableName"
              ],
              "properties": {
                "url": {
                  "type": "string"
                },
                "feedType": {
                  "type": "string",
                  "enum": [
                    "rss-xml",
                    "json"
                  ],
                  "description": "\"rss-xml\" covers both RSS and Atom XML feeds - which one it actually is gets auto-detected from the feed content itself, which changes the array key inside the template (see variableName below)."
                },
                "variableName": {
                  "type": "string",
                  "description": "No spaces allowed. This becomes a top-level Handlebars variable in the document (see the `document` field on \nthe parent email for the templating syntax). The feed's parsed items are NOT directly at `{{variableName}}` - \nthey're nested under a feed-shape-dependent array key you loop over with the custom `each` helper:\n  - feedType \"rss-xml\" that turns out to be RSS: `{{#each <variableName>.item}}...{{/each}}` (array key is the literal word \"item\", singular)\n  - feedType \"rss-xml\" that turns out to be Atom: `{{#each <variableName>.entry}}...{{/each}}` (array key is \"entry\")\n  - feedType \"json\": the array key is whatever field the source JSON actually uses for its list (e.g. \"items\", \"articles\") - inspect the feed's JSON to find it, it is not fixed.\nInside the loop, each item's own fields are whatever the feed provides (e.g. RSS gives `{{this.title}}`, `{{this.link}}`, `{{this.pubDate}}`) - there is no fixed schema, it mirrors the feed's actual content one-to-one."
                },
                "maxItems": {
                  "type": "integer",
                  "default": 5,
                  "description": "Informational only - NOT enforced when the email is sent. To actually limit how many items render, pass limit (and optionally skip) as hash arguments on the each tag itself, e.g. `{{#each news.item limit=5 skip=0}}`."
                },
                "required": {
                  "type": "boolean",
                  "default": false
                },
                "availableFields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Informational only, for the app UI - not enforced or used when rendering."
                }
              }
            },
            "description": "RSS/Atom/JSON feeds to pull into this email - see variableName on each feed for how to reference it from document."
          }
        }
      },
      "TransactionalEmail": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string"
          },
          "senderIdentity": {
            "type": "string"
          },
          "replyTo": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "chamaileon",
              "html",
              "text"
            ]
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "url",
                "feedType",
                "variableName"
              ],
              "properties": {
                "url": {
                  "type": "string"
                },
                "feedType": {
                  "type": "string",
                  "enum": [
                    "rss-xml",
                    "json"
                  ],
                  "description": "\"rss-xml\" covers both RSS and Atom XML feeds - which one it actually is gets auto-detected from the feed content itself, which changes the array key inside the template (see variableName below)."
                },
                "variableName": {
                  "type": "string",
                  "description": "No spaces allowed. This becomes a top-level Handlebars variable in the document (see the `document` field on \nthe parent email for the templating syntax). The feed's parsed items are NOT directly at `{{variableName}}` - \nthey're nested under a feed-shape-dependent array key you loop over with the custom `each` helper:\n  - feedType \"rss-xml\" that turns out to be RSS: `{{#each <variableName>.item}}...{{/each}}` (array key is the literal word \"item\", singular)\n  - feedType \"rss-xml\" that turns out to be Atom: `{{#each <variableName>.entry}}...{{/each}}` (array key is \"entry\")\n  - feedType \"json\": the array key is whatever field the source JSON actually uses for its list (e.g. \"items\", \"articles\") - inspect the feed's JSON to find it, it is not fixed.\nInside the loop, each item's own fields are whatever the feed provides (e.g. RSS gives `{{this.title}}`, `{{this.link}}`, `{{this.pubDate}}`) - there is no fixed schema, it mirrors the feed's actual content one-to-one."
                },
                "maxItems": {
                  "type": "integer",
                  "default": 5,
                  "description": "Informational only - NOT enforced when the email is sent. To actually limit how many items render, pass limit (and optionally skip) as hash arguments on the each tag itself, e.g. `{{#each news.item limit=5 skip=0}}`."
                },
                "required": {
                  "type": "boolean",
                  "default": false
                },
                "availableFields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Informational only, for the app UI - not enforced or used when rendering."
                }
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TransactionalEmailInput": {
        "type": "object",
        "required": [
          "name",
          "subject"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string",
            "description": "Optional, but meaningfully affects open rates - if the user hasn't given you one, ask what they'd like it to say rather than leaving it blank."
          },
          "senderIdentity": {
            "type": "string",
            "description": "A sender identity _id. If the user hasn't told you which one to use, call GET /v1/projectId/{projectId}/sender-identities first and ask them to choose from the real email addresses returned - don't ask them for a raw ID."
          },
          "replyTo": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "html",
              "text"
            ],
            "description": "Omit to keep using the visual (Chamaileon) editor document. Set to \"html\" or \"text\" to author document as a raw Handlebars template string instead (see the document field)."
          },
          "document": {
            "description": "The email content. When type is omitted, this is opaque Chamaileon visual-editor JSON - not meant to be hand-authored. \nWhen type is \"html\" or \"text\", this is a plain string rendered with Handlebars at send time, and can use merge tags:\n  - `{{contact.email}}`, `{{contact.name}}`, and `{{contact.<yourCustomFieldName>}}` for any field from GET /v1/projectId/{projectId}/contacts/fields.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - Any feed's variableName (see the feeds field) as a loop, e.g. `{{#each news.item limit=5 skip=0}}...{{this.title}}...{{/each}}`.\n  - Standard `{{#if}}`/`{{#unless}}`, plus custom helpers AND, OR, NOT, EQ, INCLUDES, CAPITALIZE, TRUNCATE, DEFAULT, usable like `{{#if (EQ contact.plan \"pro\")}}...{{/if}}`.\nFor transactional/triggered sends, whatever object is passed as `data` on POST /v1/projectId/{projectId}/send-transactional or /v1/projectId/{projectId}/send-triggered is merged directly into the TOP LEVEL of the template context (not nested under a \"data\" key) - so sending `data: { \"orderId\": 123 }` makes `{{orderId}}` available, not `{{data.orderId}}`."
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "url",
                "feedType",
                "variableName"
              ],
              "properties": {
                "url": {
                  "type": "string"
                },
                "feedType": {
                  "type": "string",
                  "enum": [
                    "rss-xml",
                    "json"
                  ],
                  "description": "\"rss-xml\" covers both RSS and Atom XML feeds - which one it actually is gets auto-detected from the feed content itself, which changes the array key inside the template (see variableName below)."
                },
                "variableName": {
                  "type": "string",
                  "description": "No spaces allowed. This becomes a top-level Handlebars variable in the document (see the `document` field on \nthe parent email for the templating syntax). The feed's parsed items are NOT directly at `{{variableName}}` - \nthey're nested under a feed-shape-dependent array key you loop over with the custom `each` helper:\n  - feedType \"rss-xml\" that turns out to be RSS: `{{#each <variableName>.item}}...{{/each}}` (array key is the literal word \"item\", singular)\n  - feedType \"rss-xml\" that turns out to be Atom: `{{#each <variableName>.entry}}...{{/each}}` (array key is \"entry\")\n  - feedType \"json\": the array key is whatever field the source JSON actually uses for its list (e.g. \"items\", \"articles\") - inspect the feed's JSON to find it, it is not fixed.\nInside the loop, each item's own fields are whatever the feed provides (e.g. RSS gives `{{this.title}}`, `{{this.link}}`, `{{this.pubDate}}`) - there is no fixed schema, it mirrors the feed's actual content one-to-one."
                },
                "maxItems": {
                  "type": "integer",
                  "default": 5,
                  "description": "Informational only - NOT enforced when the email is sent. To actually limit how many items render, pass limit (and optionally skip) as hash arguments on the each tag itself, e.g. `{{#each news.item limit=5 skip=0}}`."
                },
                "required": {
                  "type": "boolean",
                  "default": false
                },
                "availableFields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Informational only, for the app UI - not enforced or used when rendering."
                }
              }
            },
            "description": "RSS/Atom/JSON feeds to pull into this email - see variableName on each feed for how to reference it from document."
          }
        }
      },
      "TriggeredEmail": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string"
          },
          "subscriberListId": {
            "type": "string"
          },
          "senderIdentity": {
            "type": "string"
          },
          "replyTo": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "chamaileon",
              "html",
              "text"
            ]
          },
          "excludeUnengaged": {
            "type": "boolean"
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "url",
                "feedType",
                "variableName"
              ],
              "properties": {
                "url": {
                  "type": "string"
                },
                "feedType": {
                  "type": "string",
                  "enum": [
                    "rss-xml",
                    "json"
                  ],
                  "description": "\"rss-xml\" covers both RSS and Atom XML feeds - which one it actually is gets auto-detected from the feed content itself, which changes the array key inside the template (see variableName below)."
                },
                "variableName": {
                  "type": "string",
                  "description": "No spaces allowed. This becomes a top-level Handlebars variable in the document (see the `document` field on \nthe parent email for the templating syntax). The feed's parsed items are NOT directly at `{{variableName}}` - \nthey're nested under a feed-shape-dependent array key you loop over with the custom `each` helper:\n  - feedType \"rss-xml\" that turns out to be RSS: `{{#each <variableName>.item}}...{{/each}}` (array key is the literal word \"item\", singular)\n  - feedType \"rss-xml\" that turns out to be Atom: `{{#each <variableName>.entry}}...{{/each}}` (array key is \"entry\")\n  - feedType \"json\": the array key is whatever field the source JSON actually uses for its list (e.g. \"items\", \"articles\") - inspect the feed's JSON to find it, it is not fixed.\nInside the loop, each item's own fields are whatever the feed provides (e.g. RSS gives `{{this.title}}`, `{{this.link}}`, `{{this.pubDate}}`) - there is no fixed schema, it mirrors the feed's actual content one-to-one."
                },
                "maxItems": {
                  "type": "integer",
                  "default": 5,
                  "description": "Informational only - NOT enforced when the email is sent. To actually limit how many items render, pass limit (and optionally skip) as hash arguments on the each tag itself, e.g. `{{#each news.item limit=5 skip=0}}`."
                },
                "required": {
                  "type": "boolean",
                  "default": false
                },
                "availableFields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Informational only, for the app UI - not enforced or used when rendering."
                }
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TriggeredEmailInput": {
        "type": "object",
        "required": [
          "name",
          "subject",
          "subscriberListId"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "subscriberListId": {
            "type": "string",
            "description": "Required. If the user hasn't told you which list this triggered email is for, call GET /v1/projectId/{projectId}/subscriber-lists first and ask them to choose from the real list names - don't ask them for a raw ID."
          },
          "excludeUnengaged": {
            "type": "boolean"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string",
            "description": "Optional, but meaningfully affects open rates - if the user hasn't given you one, ask what they'd like it to say rather than leaving it blank."
          },
          "senderIdentity": {
            "type": "string",
            "description": "A sender identity _id. If the user hasn't told you which one to use, call GET /v1/projectId/{projectId}/sender-identities first and ask them to choose from the real email addresses returned - don't ask them for a raw ID."
          },
          "replyTo": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "html",
              "text"
            ],
            "description": "Omit to keep using the visual (Chamaileon) editor document. Set to \"html\" or \"text\" to author document as a raw Handlebars template string instead (see the document field)."
          },
          "document": {
            "description": "The email content. When type is omitted, this is opaque Chamaileon visual-editor JSON - not meant to be hand-authored. \nWhen type is \"html\" or \"text\", this is a plain string rendered with Handlebars at send time, and can use merge tags:\n  - `{{contact.email}}`, `{{contact.name}}`, and `{{contact.<yourCustomFieldName>}}` for any field from GET /v1/projectId/{projectId}/contacts/fields.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - Any feed's variableName (see the feeds field) as a loop, e.g. `{{#each news.item limit=5 skip=0}}...{{this.title}}...{{/each}}`.\n  - Standard `{{#if}}`/`{{#unless}}`, plus custom helpers AND, OR, NOT, EQ, INCLUDES, CAPITALIZE, TRUNCATE, DEFAULT, usable like `{{#if (EQ contact.plan \"pro\")}}...{{/if}}`.\nFor transactional/triggered sends, whatever object is passed as `data` on POST /v1/projectId/{projectId}/send-transactional or /v1/projectId/{projectId}/send-triggered is merged directly into the TOP LEVEL of the template context (not nested under a \"data\" key) - so sending `data: { \"orderId\": 123 }` makes `{{orderId}}` available, not `{{data.orderId}}`."
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "url",
                "feedType",
                "variableName"
              ],
              "properties": {
                "url": {
                  "type": "string"
                },
                "feedType": {
                  "type": "string",
                  "enum": [
                    "rss-xml",
                    "json"
                  ],
                  "description": "\"rss-xml\" covers both RSS and Atom XML feeds - which one it actually is gets auto-detected from the feed content itself, which changes the array key inside the template (see variableName below)."
                },
                "variableName": {
                  "type": "string",
                  "description": "No spaces allowed. This becomes a top-level Handlebars variable in the document (see the `document` field on \nthe parent email for the templating syntax). The feed's parsed items are NOT directly at `{{variableName}}` - \nthey're nested under a feed-shape-dependent array key you loop over with the custom `each` helper:\n  - feedType \"rss-xml\" that turns out to be RSS: `{{#each <variableName>.item}}...{{/each}}` (array key is the literal word \"item\", singular)\n  - feedType \"rss-xml\" that turns out to be Atom: `{{#each <variableName>.entry}}...{{/each}}` (array key is \"entry\")\n  - feedType \"json\": the array key is whatever field the source JSON actually uses for its list (e.g. \"items\", \"articles\") - inspect the feed's JSON to find it, it is not fixed.\nInside the loop, each item's own fields are whatever the feed provides (e.g. RSS gives `{{this.title}}`, `{{this.link}}`, `{{this.pubDate}}`) - there is no fixed schema, it mirrors the feed's actual content one-to-one."
                },
                "maxItems": {
                  "type": "integer",
                  "default": 5,
                  "description": "Informational only - NOT enforced when the email is sent. To actually limit how many items render, pass limit (and optionally skip) as hash arguments on the each tag itself, e.g. `{{#each news.item limit=5 skip=0}}`."
                },
                "required": {
                  "type": "boolean",
                  "default": false
                },
                "availableFields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Informational only, for the app UI - not enforced or used when rendering."
                }
              }
            },
            "description": "RSS/Atom/JSON feeds to pull into this email - see variableName on each feed for how to reference it from document."
          }
        }
      },
      "Template": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "onProjectCreation": {
            "type": "string",
            "enum": [
              "do-nothing",
              "set-as-transactional",
              "set-as-triggered",
              "set-as-campaign"
            ]
          },
          "usedVariables": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "usedComponents": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TemplateInput": {
        "type": "object",
        "required": [
          "name",
          "subject",
          "document"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string",
            "description": "On PATCH, pass an empty string to clear it."
          },
          "document": {
            "description": "The template content document (Chamaileon JSON)."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "onProjectCreation": {
            "type": "string",
            "enum": [
              "do-nothing",
              "set-as-transactional",
              "set-as-triggered",
              "set-as-campaign"
            ]
          }
        }
      },
      "Segment": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "groups": {
            "type": "array",
            "description": "OR-ed groups of AND-ed conditions - matches the segment builder in the app.",
            "items": {
              "type": "object",
              "properties": {
                "conditions": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "category": {
                        "type": "string",
                        "enum": [
                          "contact-property",
                          "engagement"
                        ],
                        "default": "contact-property"
                      },
                      "property": {
                        "type": "string",
                        "description": "A custom contact field name, or \"createdAt\". Required unless operator is \"any\" or a tag operator."
                      },
                      "operator": {
                        "type": "string",
                        "enum": [
                          "any",
                          "equals",
                          "does-not-equal",
                          "contains",
                          "does-not-contain",
                          "is-empty",
                          "is-not-empty",
                          "is-true",
                          "is-false",
                          "greater-than",
                          "greater-than-or-equal",
                          "less-than",
                          "less-than-or-equal",
                          "has-tag",
                          "does-not-have-tag",
                          "opened",
                          "not-opened",
                          "clicked",
                          "not-clicked",
                          "received",
                          "not-received",
                          "date-equals",
                          "date-before",
                          "date-after",
                          "date-in-last",
                          "date-more-than"
                        ],
                        "default": "any"
                      },
                      "value": {
                        "description": "Type depends on operator/property - string, number, boolean, or date string."
                      }
                    }
                  }
                }
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SegmentInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "groups": {
            "type": "array",
            "description": "OR-ed groups of AND-ed conditions - matches the segment builder in the app.",
            "items": {
              "type": "object",
              "properties": {
                "conditions": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "category": {
                        "type": "string",
                        "enum": [
                          "contact-property",
                          "engagement"
                        ],
                        "default": "contact-property"
                      },
                      "property": {
                        "type": "string",
                        "description": "A custom contact field name, or \"createdAt\". Required unless operator is \"any\" or a tag operator."
                      },
                      "operator": {
                        "type": "string",
                        "enum": [
                          "any",
                          "equals",
                          "does-not-equal",
                          "contains",
                          "does-not-contain",
                          "is-empty",
                          "is-not-empty",
                          "is-true",
                          "is-false",
                          "greater-than",
                          "greater-than-or-equal",
                          "less-than",
                          "less-than-or-equal",
                          "has-tag",
                          "does-not-have-tag",
                          "opened",
                          "not-opened",
                          "clicked",
                          "not-clicked",
                          "received",
                          "not-received",
                          "date-equals",
                          "date-before",
                          "date-after",
                          "date-in-last",
                          "date-more-than"
                        ],
                        "default": "any"
                      },
                      "value": {
                        "description": "Type depends on operator/property - string, number, boolean, or date string."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "SignUpForm": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "subscriberListIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "formLayout": {
            "type": "string"
          },
          "showCaptcha": {
            "type": "boolean"
          },
          "captchaType": {
            "type": "string",
            "enum": [
              "none",
              "svg",
              "turnstile"
            ]
          },
          "turnstileSiteKey": {
            "type": "string"
          },
          "turnstileSecretKeyHint": {
            "type": "string",
            "description": "The real secret is never returned - this is a decrypt-and-mask hint showing it's set (e.g. \"ab**...**yz\")."
          },
          "turnstileTheme": {
            "type": "string",
            "enum": [
              "light",
              "dark",
              "auto"
            ]
          },
          "turnstileSize": {
            "type": "string",
            "enum": [
              "normal",
              "compact",
              "flexible"
            ]
          },
          "turnstileAppearance": {
            "type": "string",
            "enum": [
              "always",
              "execute",
              "interaction-only"
            ]
          },
          "emailPlaceholder": {
            "type": "string"
          },
          "captchaPlaceholder": {
            "type": "string"
          },
          "formFontStyle": {
            "type": "string"
          },
          "formFontColor": {
            "type": "string"
          },
          "formFontSize": {
            "type": "string"
          },
          "btnLabel": {
            "type": "string"
          },
          "btnFont": {
            "type": "string"
          },
          "btnFontColor": {
            "type": "string"
          },
          "btnColor": {
            "type": "string"
          },
          "btnFontSize": {
            "type": "string"
          },
          "successMessage": {
            "type": "string"
          },
          "successFont": {
            "type": "string"
          },
          "successFontColor": {
            "type": "string"
          },
          "successFontSize": {
            "type": "string"
          },
          "redirectLink": {
            "type": "string",
            "description": "Where a visitor lands immediately after submitting the form - used when double opt-in is off, or is on but not yet confirmed. Different from doubleOptIn.redirectLink below."
          },
          "termsAndConditions": {
            "type": "object",
            "properties": {
              "show": {
                "type": "boolean"
              },
              "label": {
                "type": "string"
              },
              "linkLabel": {
                "type": "string"
              },
              "link": {
                "type": "string"
              }
            }
          },
          "propertiesStyle": {
            "type": "object",
            "description": "Per custom-contact-field display settings, keyed by field name: { show, required, placeholder, order }."
          },
          "doubleOptIn": {
            "type": "object",
            "properties": {
              "active": {
                "type": "boolean"
              },
              "redirectLink": {
                "type": "string",
                "description": "Where a visitor lands after clicking the confirmation link in their email. Only relevant when active is true. Different from the top-level redirectLink above."
              },
              "emailId": {
                "type": "string",
                "description": "A transactional email _id used to send the confirmation email. Its content must include {{verifyLink}}."
              },
              "confirmationTitle": {
                "type": "string"
              },
              "confirmationMessage": {
                "type": "string"
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SignUpFormInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "description": "doubleOptIn.emailId is required when doubleOptIn.active is true, and that email's content must include {{verifyLink}} - the API rejects enabling it otherwise.",
        "properties": {
          "name": {
            "type": "string"
          },
          "subscriberListIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "formLayout": {
            "type": "string"
          },
          "showCaptcha": {
            "type": "boolean"
          },
          "captchaType": {
            "type": "string",
            "enum": [
              "none",
              "svg",
              "turnstile"
            ]
          },
          "turnstileSiteKey": {
            "type": "string"
          },
          "turnstileSecretKey": {
            "type": "string",
            "description": "Write-only - never returned. Encrypted at rest."
          },
          "turnstileTheme": {
            "type": "string",
            "enum": [
              "light",
              "dark",
              "auto"
            ]
          },
          "turnstileSize": {
            "type": "string",
            "enum": [
              "normal",
              "compact",
              "flexible"
            ]
          },
          "turnstileAppearance": {
            "type": "string",
            "enum": [
              "always",
              "execute",
              "interaction-only"
            ]
          },
          "emailPlaceholder": {
            "type": "string"
          },
          "captchaPlaceholder": {
            "type": "string"
          },
          "formFontStyle": {
            "type": "string"
          },
          "formFontColor": {
            "type": "string"
          },
          "formFontSize": {
            "type": "string"
          },
          "btnLabel": {
            "type": "string"
          },
          "btnFont": {
            "type": "string"
          },
          "btnFontColor": {
            "type": "string"
          },
          "btnColor": {
            "type": "string"
          },
          "btnFontSize": {
            "type": "string"
          },
          "successMessage": {
            "type": "string"
          },
          "successFont": {
            "type": "string"
          },
          "successFontColor": {
            "type": "string"
          },
          "successFontSize": {
            "type": "string"
          },
          "redirectLink": {
            "type": "string"
          },
          "termsAndConditions": {
            "type": "object",
            "properties": {
              "show": {
                "type": "boolean"
              },
              "label": {
                "type": "string"
              },
              "linkLabel": {
                "type": "string"
              },
              "link": {
                "type": "string"
              }
            }
          },
          "propertiesStyle": {
            "type": "object"
          },
          "doubleOptIn": {
            "type": "object",
            "description": "Replaces the whole object when given - to change just one field, GET the current value first and send all five back together. Do not include the GET response's doubleOptIn._id - it is Mongoose's own subdocument id, not a real field, and PATCH rejects it as unexpected.",
            "properties": {
              "active": {
                "type": "boolean"
              },
              "redirectLink": {
                "type": "string"
              },
              "emailId": {
                "type": "string"
              },
              "confirmationTitle": {
                "type": "string"
              },
              "confirmationMessage": {
                "type": "string"
              }
            }
          }
        }
      },
      "SubscriberList": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "private": {
            "type": "boolean"
          },
          "doubleOptIn": {
            "type": "object",
            "properties": {
              "active": {
                "type": "boolean"
              },
              "redirectLink": {
                "type": "string"
              },
              "emailId": {
                "type": "string",
                "description": "A transactional email _id used to send the confirmation email."
              },
              "confirmationTitle": {
                "type": "string"
              },
              "confirmationMessage": {
                "type": "string"
              }
            }
          },
          "signupForm": {
            "type": "object",
            "properties": {
              "formLayout": {
                "type": "string"
              },
              "showCaptcha": {
                "type": "boolean"
              },
              "emailPlaceholder": {
                "type": "string"
              },
              "captchaPlaceholder": {
                "type": "string"
              },
              "formFontStyle": {
                "type": "string"
              },
              "formFontColor": {
                "type": "string"
              },
              "formFontSize": {
                "type": "string"
              },
              "btnLabel": {
                "type": "string"
              },
              "btnFont": {
                "type": "string"
              },
              "btnFontColor": {
                "type": "string"
              },
              "btnColor": {
                "type": "string"
              },
              "btnFontSize": {
                "type": "string"
              },
              "successMessage": {
                "type": "string"
              },
              "successFont": {
                "type": "string"
              },
              "successFontColor": {
                "type": "string"
              },
              "successFontSize": {
                "type": "string"
              },
              "propertiesStyle": {
                "type": "object"
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SubscriberListInput": {
        "type": "object",
        "required": [
          "name",
          "description"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "private": {
            "type": "boolean",
            "default": false
          },
          "doubleOptIn": {
            "type": "object",
            "description": "emailId is required when active is true. When active is true, the referenced transactional email's content must include {{verifyLink}} - the API rejects the request with a 400 otherwise, since that's the only way a contact can confirm their subscription. Replaces the whole object when given - to change just one field, GET the current value first and send all five back together. Do not include the GET response's doubleOptIn._id - it is Mongoose's own subdocument id, not a real field, and PATCH rejects it as unexpected.",
            "properties": {
              "active": {
                "type": "boolean"
              },
              "redirectLink": {
                "type": "string"
              },
              "emailId": {
                "type": "string",
                "description": "A transactional email _id used to send the confirmation email - NOT a template ID, even though a template may look interchangeable. Its content must include {{verifyLink}} if active is true. If the user wants double opt-in but hasn't said which email to use, call GET /v1/projectId/{projectId}/transactional-emails first and ask them to choose from the real names."
              },
              "confirmationTitle": {
                "type": "string"
              },
              "confirmationMessage": {
                "type": "string"
              }
            }
          },
          "signupForm": {
            "type": "object",
            "description": "Replaces the whole object when given, not a per-field merge - GET the current value first and send back every field you want to keep alongside your changes. Do not include the GET response's signupForm._id - it is Mongoose's own subdocument id, not a real field, and PATCH rejects it as unexpected."
          }
        }
      },
      "SenderIdentity": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "region": {
            "type": "string"
          }
        }
      },
      "SenderIdentityInput": {
        "type": "object",
        "required": [
          "email",
          "region"
        ],
        "properties": {
          "email": {
            "type": "string",
            "description": "The domain part must match a verified domain on this project in the given region."
          },
          "name": {
            "type": "string"
          },
          "region": {
            "type": "string",
            "example": "eu-north-1"
          }
        }
      },
      "Domain": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "tenant": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "configurationSet": {
                "type": "string"
              }
            }
          },
          "requiredDns": {
            "type": "object",
            "description": "DNS records (DKIM CNAMEs, SPF, MX, DMARC) the domain owner must add."
          },
          "observed": {
            "type": "object",
            "description": "Last-checked DNS verification state, per record.",
            "properties": {
              "spf": {
                "type": "object",
                "properties": {
                  "present": {
                    "type": "boolean"
                  },
                  "raw": {
                    "type": "string"
                  },
                  "checkedAt": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              "dmarc": {
                "type": "object",
                "properties": {
                  "present": {
                    "type": "boolean"
                  },
                  "raw": {
                    "type": "string"
                  },
                  "checkedAt": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              "mx": {
                "type": "object",
                "properties": {
                  "present": {
                    "type": "boolean"
                  },
                  "raw": {
                    "type": "string"
                  },
                  "checkedAt": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              "dkim": {
                "type": "object",
                "properties": {
                  "selectors": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "allOk": {
                    "type": "boolean"
                  },
                  "checkedAt": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              "allOk": {
                "type": "boolean",
                "description": "True only when SPF, DMARC, MX, and DKIM are all present/verified."
              }
            }
          }
        }
      },
      "DomainInput": {
        "type": "object",
        "required": [
          "domain",
          "region"
        ],
        "properties": {
          "domain": {
            "type": "string"
          },
          "region": {
            "type": "string",
            "example": "eu-north-1"
          }
        }
      },
      "EmailStats": {
        "type": "object",
        "description": "Aggregate counts for a single campaign/transactional/triggered email, optionally within a from/to date range.",
        "properties": {
          "opens": {
            "type": "integer",
            "description": "Total open events (a single recipient opening twice counts twice)."
          },
          "clicks": {
            "type": "integer",
            "description": "Total click events."
          },
          "uniqueOpens": {
            "type": "integer",
            "description": "Number of distinct dispatched emails with at least one open."
          },
          "uniqueClicks": {
            "type": "integer",
            "description": "Number of distinct dispatched emails with at least one click."
          },
          "sent": {
            "type": "integer"
          },
          "failed": {
            "type": "integer"
          },
          "bounce": {
            "type": "integer"
          },
          "complaint": {
            "type": "integer"
          }
        }
      },
      "DispatchedEmailRecipient": {
        "type": "object",
        "description": "One row per actual recipient of a single campaign/transactional/triggered send.",
        "properties": {
          "email": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "being-sent",
              "sent",
              "failed"
            ]
          },
          "sentAt": {
            "type": "string",
            "format": "date-time"
          },
          "opens": {
            "type": "integer",
            "description": "Number of times this recipient opened this specific send."
          },
          "clicks": {
            "type": "integer",
            "description": "Number of times this recipient clicked a link in this specific send."
          },
          "bounced": {
            "type": "boolean"
          },
          "complained": {
            "type": "boolean"
          },
          "unsubscribed": {
            "type": "boolean",
            "description": "True if this recipient unsubscribed via the link in this specific send."
          },
          "paused": {
            "type": "boolean"
          },
          "subscribed": {
            "type": "boolean"
          },
          "resubscribed": {
            "type": "boolean"
          },
          "errors": {
            "type": "array",
            "items": {},
            "description": "Present when status is \"failed\" - why the send failed."
          }
        }
      },
      "SubscriberListStats": {
        "type": "object",
        "description": "active/paused/unsubscribed/unverified are a current snapshot (not affected by from/to). The rest count events within the optional from/to date range.",
        "properties": {
          "active": {
            "type": "integer"
          },
          "paused": {
            "type": "integer"
          },
          "unsubscribed": {
            "type": "integer"
          },
          "unverified": {
            "type": "integer"
          },
          "subscribed": {
            "type": "integer",
            "description": "subscribe events in range."
          },
          "unsubscribedEvents": {
            "type": "integer"
          },
          "pausedEvents": {
            "type": "integer"
          },
          "unpausedEvents": {
            "type": "integer"
          },
          "bounce": {
            "type": "integer"
          },
          "complaint": {
            "type": "integer"
          }
        }
      },
      "SuppressionListEntry": {
        "type": "object",
        "description": "A PROJECT-level suppression entry - this only blocks sends within this one project. It is a separate list from the \naccount-wide bounce/complaint suppression list (populated automatically from real bounces/complaints across every \nproject), which has no public API and can only be managed by an admin. Adding an email here does block sends to it \nfrom this project (POST /v1/projectId/{projectId}/send-transactional, /v1/projectId/{projectId}/send-triggered, campaigns, contact/subscription creation all check it).",
        "properties": {
          "_id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SuppressionListEntryInput": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "ContactTag": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "value": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ContactTagInput": {
        "type": "object",
        "required": [
          "value"
        ],
        "properties": {
          "value": {
            "type": "string"
          }
        }
      },
      "ContactField": {
        "type": "object",
        "required": [
          "name",
          "type"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "string",
              "number",
              "boolean",
              "date"
            ]
          }
        }
      },
      "Contact": {
        "type": "object",
        "description": "Custom contact field values are sent/received as flat top-level keys matching the field's name, not nested under \na \"customFields\" object - e.g. after creating a field named \"plan\" via POST /v1/projectId/{projectId}/contacts/fields, \nset it with `{ \"email\": \"x@y.com\", \"plan\": \"pro\" }`. A key that does not match any registered field name is silently \ndropped (not an error) - it will not appear in the response, so a typo in a custom field name fails silently.",
        "properties": {
          "_id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "_lists": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names of subscriber lists this contact belongs to."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": true
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "secretKey": {
            "type": "string"
          },
          "bounce": {
            "type": "boolean"
          },
          "complaint": {
            "type": "boolean"
          },
          "click": {
            "type": "boolean"
          },
          "open": {
            "type": "boolean"
          },
          "sent": {
            "type": "boolean"
          },
          "failed": {
            "type": "boolean"
          },
          "subscription": {
            "type": "boolean"
          }
        }
      },
      "WebhookInput": {
        "type": "object",
        "required": [
          "url",
          "secretKey"
        ],
        "properties": {
          "url": {
            "type": "string"
          },
          "secretKey": {
            "type": "string",
            "description": "Must match one of this project's existing API keys (managed in the app under Project Settings > API Keys - not exposed via this API)."
          },
          "bounce": {
            "type": "boolean"
          },
          "complaint": {
            "type": "boolean"
          },
          "click": {
            "type": "boolean"
          },
          "open": {
            "type": "boolean"
          },
          "sent": {
            "type": "boolean"
          },
          "failed": {
            "type": "boolean"
          },
          "subscription": {
            "type": "boolean"
          }
        }
      },
      "Project": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "logoUrl": {
            "type": "string"
          },
          "designSystemId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "sandbox",
              "production",
              "byoAwsSes"
            ],
            "description": "New projects start as \"sandbox\". Sandbox recipients are not restricted, but sending is rate-limited to a \nlow daily cap (a 405 once exceeded, see GET .../sandbox/deliverability) and gets automatically restricted \n(see the restricted field) if bounce/complaint rates run high. To leave sandbox for real production sending, \nverify a domain and POST .../production-access - approval is manual, see the Production Access endpoints below."
          },
          "restricted": {
            "type": "boolean",
            "description": "Read-only - set automatically (high bounce/complaint rates) or by bluefox.email staff, never by this API. \nA restricted, non-byoAwsSes project cannot send at all, regardless of production-access status - applying for \nor already having production access does not lift a restriction, since the restriction is on bluefox.email's \nshared sending infrastructure specifically. The only way for a restricted project to resume sending is to \nswitch to BYO-AWS (PATCH .../projectId/{projectId} awsConfig + status: \"byoAwsSes\"), which uses the project's \nown AWS account instead of the shared infrastructure."
          },
          "restrictedReason": {
            "type": "string",
            "nullable": true,
            "description": "Read-only. Human-readable reason, present only when restricted is true."
          },
          "unengagedContactSegment": {
            "type": "object",
            "properties": {
              "groups": {
                "type": "array",
                "description": "OR-ed groups of AND-ed conditions - matches the segment builder in the app.",
                "items": {
                  "type": "object",
                  "properties": {
                    "conditions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "category": {
                            "type": "string",
                            "enum": [
                              "contact-property",
                              "engagement"
                            ],
                            "default": "contact-property"
                          },
                          "property": {
                            "type": "string",
                            "description": "A custom contact field name, or \"createdAt\". Required unless operator is \"any\" or a tag operator."
                          },
                          "operator": {
                            "type": "string",
                            "enum": [
                              "any",
                              "equals",
                              "does-not-equal",
                              "contains",
                              "does-not-contain",
                              "is-empty",
                              "is-not-empty",
                              "is-true",
                              "is-false",
                              "greater-than",
                              "greater-than-or-equal",
                              "less-than",
                              "less-than-or-equal",
                              "has-tag",
                              "does-not-have-tag",
                              "opened",
                              "not-opened",
                              "clicked",
                              "not-clicked",
                              "received",
                              "not-received",
                              "date-equals",
                              "date-before",
                              "date-after",
                              "date-in-last",
                              "date-more-than"
                            ],
                            "default": "any"
                          },
                          "value": {
                            "description": "Type depends on operator/property - string, number, boolean, or date string."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "awsConfig": {
            "$ref": "#/components/schemas/AwsConfig"
          },
          "monthlyLimit": {
            "type": "integer"
          },
          "autoRemoveFromList": {
            "$ref": "#/components/schemas/AutoRemoveFromList"
          },
          "whiteList": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Domains (bare, e.g. \"example.com\" - no protocol) allowed to call certain endpoints (like the direct subscribe-to-list endpoint) straight from browser JavaScript, by Origin header, without an API key."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProjectInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "logoUrl": {
            "type": "string",
            "description": "Pass an empty string to remove the logo."
          },
          "unengagedContactSegment": {
            "type": "object",
            "properties": {
              "groups": {
                "type": "array",
                "description": "OR-ed groups of AND-ed conditions - matches the segment builder in the app.",
                "items": {
                  "type": "object",
                  "properties": {
                    "conditions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "category": {
                            "type": "string",
                            "enum": [
                              "contact-property",
                              "engagement"
                            ],
                            "default": "contact-property"
                          },
                          "property": {
                            "type": "string",
                            "description": "A custom contact field name, or \"createdAt\". Required unless operator is \"any\" or a tag operator."
                          },
                          "operator": {
                            "type": "string",
                            "enum": [
                              "any",
                              "equals",
                              "does-not-equal",
                              "contains",
                              "does-not-contain",
                              "is-empty",
                              "is-not-empty",
                              "is-true",
                              "is-false",
                              "greater-than",
                              "greater-than-or-equal",
                              "less-than",
                              "less-than-or-equal",
                              "has-tag",
                              "does-not-have-tag",
                              "opened",
                              "not-opened",
                              "clicked",
                              "not-clicked",
                              "received",
                              "not-received",
                              "date-equals",
                              "date-before",
                              "date-after",
                              "date-in-last",
                              "date-more-than"
                            ],
                            "default": "any"
                          },
                          "value": {
                            "description": "Type depends on operator/property - string, number, boolean, or date string."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "awsConfig": {
            "$ref": "#/components/schemas/AwsConfigInput"
          },
          "status": {
            "type": "string",
            "enum": [
              "byoAwsSes"
            ],
            "description": "Any other value is ignored - this can only be used to switch INTO byoAwsSes, not to set sandbox/production directly (those come from the production-access review flow)."
          },
          "autoRemoveFromList": {
            "$ref": "#/components/schemas/AutoRemoveFromList"
          },
          "whiteList": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replaces the whole list. Bare domains only (e.g. \"example.com\"), no protocol or path."
          }
        }
      },
      "AutoRemoveFromList": {
        "type": "object",
        "description": "What happens to a contact automatically when they bounce or complain. Sent/returned as a whole object - PATCHing just one of bounce/complaint replaces the other with its default, it is not a per-key merge.",
        "properties": {
          "bounce": {
            "type": "string",
            "enum": [
              "off",
              "removeFromLists",
              "deleteContact"
            ],
            "default": "removeFromLists",
            "description": "\"off\" leaves subscriptions untouched, \"removeFromLists\" unsubscribes the contact from every list, \"deleteContact\" also deletes the contact."
          },
          "complaint": {
            "type": "string",
            "enum": [
              "off",
              "removeFromLists",
              "deleteContact"
            ],
            "default": "removeFromLists",
            "description": "Same modes as bounce, applied on a spam complaint instead."
          }
        }
      },
      "DesignSystemEntry": {
        "type": "object",
        "description": "main and description are only ever populated on variables.*/font.* entries, never on components.* entries - the override PATCH silently drops both for category: \"components\".",
        "properties": {
          "name": {
            "type": "string",
            "description": "Matches an entry's name is required when calling PATCH .../design-systems/{id} to override or reset it."
          },
          "value": {
            "description": "Shape depends on category/key - e.g. a hex color string, a font stack string, or a style object for a component."
          },
          "main": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "overridden": {
            "type": "boolean",
            "description": "True when this project has its own override for this entry, as opposed to inheriting the base design system's value."
          }
        }
      },
      "DesignSystem": {
        "type": "object",
        "description": "The design system merged with this project's overrides (designSystemParams) - what the project actually renders with.",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "variables": {
            "type": "object",
            "properties": {
              "colors": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              },
              "fontStacks": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              },
              "images": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              },
              "links": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              },
              "texts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              }
            }
          },
          "font": {
            "type": "object",
            "properties": {
              "resources": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              },
              "stacks": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              }
            }
          },
          "components": {
            "type": "object",
            "properties": {
              "buttons": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              },
              "texts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              },
              "images": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              },
              "dividers": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DesignSystemEntry"
                }
              }
            }
          }
        },
        "additionalProperties": true
      },
      "DesignSystemPatch": {
        "type": "object",
        "properties": {
          "setOverrides": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "category",
                "key",
                "name",
                "value"
              ],
              "properties": {
                "category": {
                  "type": "string",
                  "enum": [
                    "variables",
                    "font",
                    "components"
                  ]
                },
                "key": {
                  "type": "string",
                  "description": "variables: colors|fontStacks|images|links|texts. font: resources|stacks. components: buttons|texts|images|dividers."
                },
                "name": {
                  "type": "string"
                },
                "value": {
                  "description": "Any value - shape depends on category/key."
                },
                "main": {
                  "type": "boolean"
                },
                "description": {
                  "type": "string"
                }
              }
            }
          },
          "resetOverrides": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "category",
                "key",
                "name"
              ],
              "properties": {
                "category": {
                  "type": "string",
                  "enum": [
                    "variables",
                    "font",
                    "components"
                  ]
                },
                "key": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ProductionAccessReqInput": {
        "type": "object",
        "required": [
          "volume",
          "whyBluefox",
          "typeOfEmails",
          "contactsSource",
          "productDescription",
          "website"
        ],
        "properties": {
          "volume": {
            "type": "integer",
            "description": "Expected monthly sending volume."
          },
          "whyBluefox": {
            "type": "string"
          },
          "typeOfEmails": {
            "type": "string"
          },
          "contactsSource": {
            "type": "string"
          },
          "productDescription": {
            "type": "string"
          },
          "website": {
            "type": "string"
          }
        }
      },
      "ProductionAccessLimitIncrease": {
        "type": "object",
        "properties": {
          "requestedLimit": {
            "type": "integer"
          },
          "approvedLimit": {
            "type": "integer"
          },
          "reason": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "declined"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProductionAccessStatus": {
        "type": "object",
        "properties": {
          "requestStatus": {
            "type": "string",
            "enum": [
              "none",
              "pending",
              "approved",
              "declined",
              "revoked"
            ],
            "description": "\"none\" means no request has been submitted yet."
          },
          "domainStatus": {
            "type": "string",
            "enum": [
              "none",
              "pending",
              "verified"
            ]
          },
          "verifiedDomain": {
            "type": "string",
            "description": "Empty string if none is verified yet."
          },
          "monthlyLimit": {
            "type": "integer"
          },
          "sendingRates": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "region": {
                  "type": "string"
                },
                "ratePerSecond": {
                  "type": "integer"
                }
              }
            }
          },
          "limitIncreases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProductionAccessLimitIncrease"
            }
          },
          "restricted": {
            "type": "boolean",
            "description": "True if the project is currently blocked from sending on bluefox.email's shared infrastructure (see Project.restricted). Approval here does not lift a restriction - switch to BYO-AWS instead if this is true."
          },
          "restrictedReason": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "LimitIncreaseInput": {
        "type": "object",
        "required": [
          "monthlyLimit",
          "reason"
        ],
        "properties": {
          "monthlyLimit": {
            "type": "integer",
            "description": "Must be higher than the project's current monthlyLimit, except 0 which is always accepted (used to reset/clear the limit)."
          },
          "reason": {
            "type": "string",
            "description": "At least 10 characters."
          }
        }
      },
      "AwsConfigInput": {
        "type": "object",
        "description": "Only for projects that want to send through their own AWS account - most projects should use POST .../production-access instead to raise limits on bluefox.email's shared infrastructure without managing AWS themselves. roleArn is mutually exclusive with accessKeyId/secretAccessKey - providing both is a 405. Only send the fields you want to change; anything omitted keeps its current stored value.",
        "properties": {
          "roleArn": {
            "type": "string",
            "description": "STS role ARN from the CloudFormation setup (see GET .../cloudformation-link)."
          },
          "accessKeyId": {
            "type": "string"
          },
          "secretAccessKey": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "limit": {
            "type": "integer",
            "description": "Max sends per second."
          },
          "senderIdentities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "_id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "email": {
                  "type": "string"
                }
              }
            }
          },
          "removeAwsConfig": {
            "type": "string",
            "enum": [
              "sts",
              "accessKey"
            ],
            "description": "Clears just the STS role, or just the static keys - leaving the other half (if set) intact."
          }
        }
      },
      "AwsConfig": {
        "type": "object",
        "description": "Secrets are never returned raw - only masked hints. Empty/absent is normal and expected for a project that isn't status: \"byoAwsSes\" - it just means the project sends through bluefox.email's shared infrastructure instead; see GET .../production-access for that project's status there.",
        "properties": {
          "region": {
            "type": "string"
          },
          "limit": {
            "type": "integer"
          },
          "senderIdentities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "email": {
                  "type": "string"
                }
              }
            }
          },
          "accessKeyIdHint": {
            "type": "string",
            "nullable": true
          },
          "secretAccessKeyHint": {
            "type": "string",
            "nullable": true
          },
          "roleArnHint": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "AwsCheckInput": {
        "type": "object",
        "description": "Every field is optional - omit any of them to check against what's already stored on the project instead.",
        "properties": {
          "roleArn": {
            "type": "string"
          },
          "accessKeyId": {
            "type": "string"
          },
          "secretAccessKey": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "limit": {
            "type": "integer"
          },
          "senderIdentities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "_id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "email": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "CloudformationLink": {
        "type": "object",
        "properties": {
          "link": {
            "type": "string",
            "description": "CloudFormation quick-create URL for the STS role bluefox.email needs to send through this project's own AWS account."
          }
        }
      },
      "DeliverabilityWindow": {
        "type": "object",
        "properties": {
          "totalSent": {
            "type": "integer"
          },
          "totalBounces": {
            "type": "integer"
          },
          "totalComplaints": {
            "type": "integer"
          },
          "rate": {
            "type": "number",
            "description": "Percentage."
          },
          "pct": {
            "type": "number",
            "description": "This rate as a percentage of the platform's max allowed rate."
          }
        }
      },
      "SandboxDeliverability": {
        "type": "object",
        "properties": {
          "sentCount": {
            "type": "integer",
            "description": "Sandbox sends today."
          },
          "productionAccessReqStatus": {
            "type": "string",
            "nullable": true
          },
          "bounce": {
            "$ref": "#/components/schemas/DeliverabilityWindow"
          },
          "complaint": {
            "$ref": "#/components/schemas/DeliverabilityWindow"
          }
        }
      },
      "ProductionDeliverability": {
        "type": "object",
        "properties": {
          "bounce": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DeliverabilityWindow"
              },
              {
                "type": "object",
                "properties": {
                  "windowKey": {
                    "type": "string",
                    "enum": [
                      "last7d",
                      "last30d",
                      "last90d"
                    ]
                  },
                  "windowLabel": {
                    "type": "string"
                  }
                }
              }
            ]
          },
          "complaint": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DeliverabilityWindow"
              },
              {
                "type": "object",
                "properties": {
                  "windowKey": {
                    "type": "string",
                    "enum": [
                      "last7d",
                      "last30d",
                      "last90d"
                    ]
                  },
                  "windowLabel": {
                    "type": "string"
                  }
                }
              }
            ]
          },
          "domains": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "domain": {
                  "type": "string"
                },
                "region": {
                  "type": "string"
                },
                "sent": {
                  "type": "integer"
                },
                "bounces": {
                  "type": "integer"
                },
                "complaints": {
                  "type": "integer"
                }
              }
            },
            "description": "Only verified (DKIM-passing) domains."
          },
          "monthly": {
            "type": "object",
            "properties": {
              "sent": {
                "type": "integer"
              },
              "limit": {
                "type": "integer"
              }
            }
          }
        }
      },
      "TestWebhookResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          }
        }
      },
      "EmailErrorLogEntry": {
        "type": "object",
        "properties": {
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "source": {
            "type": "string",
            "enum": [
              "processing",
              "delivery"
            ]
          },
          "recipient": {
            "type": "string",
            "nullable": true,
            "description": "Only set for source \"delivery\"."
          },
          "errorName": {
            "type": "string"
          },
          "errorMessage": {
            "type": "string"
          }
        }
      },
      "EmailErrorLog": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailErrorLogEntry"
            }
          },
          "count": {
            "type": "integer"
          },
          "unseenCount": {
            "type": "integer",
            "description": "Items created after the last time this log was marked seen in the app."
          }
        }
      },
      "CampaignInputPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string",
            "description": "Optional, but meaningfully affects open rates - if the user hasn't given you one, ask what they'd like it to say rather than leaving it blank."
          },
          "timeZone": {
            "type": "string",
            "description": "IANA time zone, e.g. \"America/New_York\". Used to interpret scheduledTo."
          },
          "subscriberListId": {
            "type": "string",
            "description": "Required. If the user hasn't told you which list to send to, call GET /v1/projectId/{projectId}/subscriber-lists first and ask them to choose from the real list names - don't ask them for a raw ID."
          },
          "segmentId": {
            "type": "string",
            "description": "Optional - narrows the subscriberListId down further. If the user mentions targeting a specific segment by name but doesn't give an ID, call GET /v1/projectId/{projectId}/segments first and ask them to choose from the real names."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "archive",
              "scheduled"
            ],
            "description": "Set to \"scheduled\" together with scheduledTo to schedule sending."
          },
          "scheduledTo": {
            "type": "string",
            "format": "date-time"
          },
          "excludeUnengaged": {
            "type": "boolean"
          },
          "senderIdentity": {
            "type": "string",
            "description": "A sender identity _id. If the user hasn't told you which one to use, call GET /v1/projectId/{projectId}/sender-identities first and ask them to choose from the real email addresses returned - don't ask them for a raw ID."
          },
          "replyTo": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "html",
              "text"
            ],
            "description": "Omit to keep using the visual (Chamaileon) editor document. Set to \"html\" or \"text\" to author document as a raw Handlebars template string instead (see the document field)."
          },
          "document": {
            "description": "The email content. When type is omitted, this is opaque Chamaileon visual-editor JSON - not meant to be hand-authored. \nWhen type is \"html\" or \"text\", this is a plain string rendered with Handlebars at send time, and can use merge tags:\n  - `{{contact.email}}`, `{{contact.name}}`, and `{{contact.<yourCustomFieldName>}}` for any field from GET /v1/projectId/{projectId}/contacts/fields.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - Any feed's variableName (see the feeds field) as a loop, e.g. `{{#each news.item limit=5 skip=0}}...{{this.title}}...{{/each}}`.\n  - Standard `{{#if}}`/`{{#unless}}`, plus custom helpers AND, OR, NOT, EQ, INCLUDES, CAPITALIZE, TRUNCATE, DEFAULT, usable like `{{#if (EQ contact.plan \"pro\")}}...{{/if}}`.\nFor transactional/triggered sends, whatever object is passed as `data` on POST /v1/projectId/{projectId}/send-transactional or /v1/projectId/{projectId}/send-triggered is merged directly into the TOP LEVEL of the template context (not nested under a \"data\" key) - so sending `data: { \"orderId\": 123 }` makes `{{orderId}}` available, not `{{data.orderId}}`."
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                },
                "feedType": {
                  "type": "string",
                  "enum": [
                    "rss-xml",
                    "json"
                  ],
                  "description": "\"rss-xml\" covers both RSS and Atom XML feeds - which one it actually is gets auto-detected from the feed content itself, which changes the array key inside the template (see variableName below)."
                },
                "variableName": {
                  "type": "string",
                  "description": "No spaces allowed. This becomes a top-level Handlebars variable in the document (see the `document` field on \nthe parent email for the templating syntax). The feed's parsed items are NOT directly at `{{variableName}}` - \nthey're nested under a feed-shape-dependent array key you loop over with the custom `each` helper:\n  - feedType \"rss-xml\" that turns out to be RSS: `{{#each <variableName>.item}}...{{/each}}` (array key is the literal word \"item\", singular)\n  - feedType \"rss-xml\" that turns out to be Atom: `{{#each <variableName>.entry}}...{{/each}}` (array key is \"entry\")\n  - feedType \"json\": the array key is whatever field the source JSON actually uses for its list (e.g. \"items\", \"articles\") - inspect the feed's JSON to find it, it is not fixed.\nInside the loop, each item's own fields are whatever the feed provides (e.g. RSS gives `{{this.title}}`, `{{this.link}}`, `{{this.pubDate}}`) - there is no fixed schema, it mirrors the feed's actual content one-to-one."
                },
                "maxItems": {
                  "type": "integer",
                  "default": 5,
                  "description": "Informational only - NOT enforced when the email is sent. To actually limit how many items render, pass limit (and optionally skip) as hash arguments on the each tag itself, e.g. `{{#each news.item limit=5 skip=0}}`."
                },
                "required": {
                  "type": "boolean",
                  "default": false
                },
                "availableFields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Informational only, for the app UI - not enforced or used when rendering."
                }
              }
            },
            "description": "RSS/Atom/JSON feeds to pull into this email - see variableName on each feed for how to reference it from document."
          }
        }
      },
      "TransactionalEmailInputPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string",
            "description": "Optional, but meaningfully affects open rates - if the user hasn't given you one, ask what they'd like it to say rather than leaving it blank."
          },
          "senderIdentity": {
            "type": "string",
            "description": "A sender identity _id. If the user hasn't told you which one to use, call GET /v1/projectId/{projectId}/sender-identities first and ask them to choose from the real email addresses returned - don't ask them for a raw ID."
          },
          "replyTo": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "html",
              "text"
            ],
            "description": "Omit to keep using the visual (Chamaileon) editor document. Set to \"html\" or \"text\" to author document as a raw Handlebars template string instead (see the document field)."
          },
          "document": {
            "description": "The email content. When type is omitted, this is opaque Chamaileon visual-editor JSON - not meant to be hand-authored. \nWhen type is \"html\" or \"text\", this is a plain string rendered with Handlebars at send time, and can use merge tags:\n  - `{{contact.email}}`, `{{contact.name}}`, and `{{contact.<yourCustomFieldName>}}` for any field from GET /v1/projectId/{projectId}/contacts/fields.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - Any feed's variableName (see the feeds field) as a loop, e.g. `{{#each news.item limit=5 skip=0}}...{{this.title}}...{{/each}}`.\n  - Standard `{{#if}}`/`{{#unless}}`, plus custom helpers AND, OR, NOT, EQ, INCLUDES, CAPITALIZE, TRUNCATE, DEFAULT, usable like `{{#if (EQ contact.plan \"pro\")}}...{{/if}}`.\nFor transactional/triggered sends, whatever object is passed as `data` on POST /v1/projectId/{projectId}/send-transactional or /v1/projectId/{projectId}/send-triggered is merged directly into the TOP LEVEL of the template context (not nested under a \"data\" key) - so sending `data: { \"orderId\": 123 }` makes `{{orderId}}` available, not `{{data.orderId}}`."
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                },
                "feedType": {
                  "type": "string",
                  "enum": [
                    "rss-xml",
                    "json"
                  ],
                  "description": "\"rss-xml\" covers both RSS and Atom XML feeds - which one it actually is gets auto-detected from the feed content itself, which changes the array key inside the template (see variableName below)."
                },
                "variableName": {
                  "type": "string",
                  "description": "No spaces allowed. This becomes a top-level Handlebars variable in the document (see the `document` field on \nthe parent email for the templating syntax). The feed's parsed items are NOT directly at `{{variableName}}` - \nthey're nested under a feed-shape-dependent array key you loop over with the custom `each` helper:\n  - feedType \"rss-xml\" that turns out to be RSS: `{{#each <variableName>.item}}...{{/each}}` (array key is the literal word \"item\", singular)\n  - feedType \"rss-xml\" that turns out to be Atom: `{{#each <variableName>.entry}}...{{/each}}` (array key is \"entry\")\n  - feedType \"json\": the array key is whatever field the source JSON actually uses for its list (e.g. \"items\", \"articles\") - inspect the feed's JSON to find it, it is not fixed.\nInside the loop, each item's own fields are whatever the feed provides (e.g. RSS gives `{{this.title}}`, `{{this.link}}`, `{{this.pubDate}}`) - there is no fixed schema, it mirrors the feed's actual content one-to-one."
                },
                "maxItems": {
                  "type": "integer",
                  "default": 5,
                  "description": "Informational only - NOT enforced when the email is sent. To actually limit how many items render, pass limit (and optionally skip) as hash arguments on the each tag itself, e.g. `{{#each news.item limit=5 skip=0}}`."
                },
                "required": {
                  "type": "boolean",
                  "default": false
                },
                "availableFields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Informational only, for the app UI - not enforced or used when rendering."
                }
              }
            },
            "description": "RSS/Atom/JSON feeds to pull into this email - see variableName on each feed for how to reference it from document."
          }
        }
      },
      "TriggeredEmailInputPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "subscriberListId": {
            "type": "string",
            "description": "Required. If the user hasn't told you which list this triggered email is for, call GET /v1/projectId/{projectId}/subscriber-lists first and ask them to choose from the real list names - don't ask them for a raw ID."
          },
          "excludeUnengaged": {
            "type": "boolean"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string",
            "description": "Optional, but meaningfully affects open rates - if the user hasn't given you one, ask what they'd like it to say rather than leaving it blank."
          },
          "senderIdentity": {
            "type": "string",
            "description": "A sender identity _id. If the user hasn't told you which one to use, call GET /v1/projectId/{projectId}/sender-identities first and ask them to choose from the real email addresses returned - don't ask them for a raw ID."
          },
          "replyTo": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "html",
              "text"
            ],
            "description": "Omit to keep using the visual (Chamaileon) editor document. Set to \"html\" or \"text\" to author document as a raw Handlebars template string instead (see the document field)."
          },
          "document": {
            "description": "The email content. When type is omitted, this is opaque Chamaileon visual-editor JSON - not meant to be hand-authored. \nWhen type is \"html\" or \"text\", this is a plain string rendered with Handlebars at send time, and can use merge tags:\n  - `{{contact.email}}`, `{{contact.name}}`, and `{{contact.<yourCustomFieldName>}}` for any field from GET /v1/projectId/{projectId}/contacts/fields.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - Any feed's variableName (see the feeds field) as a loop, e.g. `{{#each news.item limit=5 skip=0}}...{{this.title}}...{{/each}}`.\n  - Standard `{{#if}}`/`{{#unless}}`, plus custom helpers AND, OR, NOT, EQ, INCLUDES, CAPITALIZE, TRUNCATE, DEFAULT, usable like `{{#if (EQ contact.plan \"pro\")}}...{{/if}}`.\nFor transactional/triggered sends, whatever object is passed as `data` on POST /v1/projectId/{projectId}/send-transactional or /v1/projectId/{projectId}/send-triggered is merged directly into the TOP LEVEL of the template context (not nested under a \"data\" key) - so sending `data: { \"orderId\": 123 }` makes `{{orderId}}` available, not `{{data.orderId}}`."
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                },
                "feedType": {
                  "type": "string",
                  "enum": [
                    "rss-xml",
                    "json"
                  ],
                  "description": "\"rss-xml\" covers both RSS and Atom XML feeds - which one it actually is gets auto-detected from the feed content itself, which changes the array key inside the template (see variableName below)."
                },
                "variableName": {
                  "type": "string",
                  "description": "No spaces allowed. This becomes a top-level Handlebars variable in the document (see the `document` field on \nthe parent email for the templating syntax). The feed's parsed items are NOT directly at `{{variableName}}` - \nthey're nested under a feed-shape-dependent array key you loop over with the custom `each` helper:\n  - feedType \"rss-xml\" that turns out to be RSS: `{{#each <variableName>.item}}...{{/each}}` (array key is the literal word \"item\", singular)\n  - feedType \"rss-xml\" that turns out to be Atom: `{{#each <variableName>.entry}}...{{/each}}` (array key is \"entry\")\n  - feedType \"json\": the array key is whatever field the source JSON actually uses for its list (e.g. \"items\", \"articles\") - inspect the feed's JSON to find it, it is not fixed.\nInside the loop, each item's own fields are whatever the feed provides (e.g. RSS gives `{{this.title}}`, `{{this.link}}`, `{{this.pubDate}}`) - there is no fixed schema, it mirrors the feed's actual content one-to-one."
                },
                "maxItems": {
                  "type": "integer",
                  "default": 5,
                  "description": "Informational only - NOT enforced when the email is sent. To actually limit how many items render, pass limit (and optionally skip) as hash arguments on the each tag itself, e.g. `{{#each news.item limit=5 skip=0}}`."
                },
                "required": {
                  "type": "boolean",
                  "default": false
                },
                "availableFields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Informational only, for the app UI - not enforced or used when rendering."
                }
              }
            },
            "description": "RSS/Atom/JSON feeds to pull into this email - see variableName on each feed for how to reference it from document."
          }
        }
      },
      "TemplateInputPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string",
            "description": "On PATCH, pass an empty string to clear it."
          },
          "document": {
            "description": "The template content document (Chamaileon JSON)."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "onProjectCreation": {
            "type": "string",
            "enum": [
              "do-nothing",
              "set-as-transactional",
              "set-as-triggered",
              "set-as-campaign"
            ]
          }
        }
      },
      "SegmentInputPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "groups": {
            "type": "array",
            "description": "OR-ed groups of AND-ed conditions - matches the segment builder in the app.",
            "items": {
              "type": "object",
              "properties": {
                "conditions": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "category": {
                        "type": "string",
                        "enum": [
                          "contact-property",
                          "engagement"
                        ],
                        "default": "contact-property"
                      },
                      "property": {
                        "type": "string",
                        "description": "A custom contact field name, or \"createdAt\". Required unless operator is \"any\" or a tag operator."
                      },
                      "operator": {
                        "type": "string",
                        "enum": [
                          "any",
                          "equals",
                          "does-not-equal",
                          "contains",
                          "does-not-contain",
                          "is-empty",
                          "is-not-empty",
                          "is-true",
                          "is-false",
                          "greater-than",
                          "greater-than-or-equal",
                          "less-than",
                          "less-than-or-equal",
                          "has-tag",
                          "does-not-have-tag",
                          "opened",
                          "not-opened",
                          "clicked",
                          "not-clicked",
                          "received",
                          "not-received",
                          "date-equals",
                          "date-before",
                          "date-after",
                          "date-in-last",
                          "date-more-than"
                        ],
                        "default": "any"
                      },
                      "value": {
                        "description": "Type depends on operator/property - string, number, boolean, or date string."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "SubscriberListInputPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "private": {
            "type": "boolean",
            "default": false
          },
          "doubleOptIn": {
            "type": "object",
            "description": "emailId is required when active is true. When active is true, the referenced transactional email's content must include {{verifyLink}} - the API rejects the request with a 400 otherwise, since that's the only way a contact can confirm their subscription. Replaces the whole object when given - to change just one field, GET the current value first and send all five back together. Do not include the GET response's doubleOptIn._id - it is Mongoose's own subdocument id, not a real field, and PATCH rejects it as unexpected.",
            "properties": {
              "active": {
                "type": "boolean"
              },
              "redirectLink": {
                "type": "string"
              },
              "emailId": {
                "type": "string",
                "description": "A transactional email _id used to send the confirmation email - NOT a template ID, even though a template may look interchangeable. Its content must include {{verifyLink}} if active is true. If the user wants double opt-in but hasn't said which email to use, call GET /v1/projectId/{projectId}/transactional-emails first and ask them to choose from the real names."
              },
              "confirmationTitle": {
                "type": "string"
              },
              "confirmationMessage": {
                "type": "string"
              }
            }
          },
          "signupForm": {
            "type": "object",
            "description": "Replaces the whole object when given, not a per-field merge - GET the current value first and send back every field you want to keep alongside your changes. Do not include the GET response's signupForm._id - it is Mongoose's own subdocument id, not a real field, and PATCH rejects it as unexpected."
          }
        }
      },
      "ContactTagInputPatch": {
        "type": "object",
        "properties": {
          "value": {
            "type": "string"
          }
        }
      },
      "SignUpFormInputPatch": {
        "type": "object",
        "description": "doubleOptIn.emailId is required when doubleOptIn.active is true, and that email's content must include {{verifyLink}} - the API rejects enabling it otherwise.",
        "properties": {
          "name": {
            "type": "string"
          },
          "subscriberListIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "formLayout": {
            "type": "string"
          },
          "showCaptcha": {
            "type": "boolean"
          },
          "captchaType": {
            "type": "string",
            "enum": [
              "none",
              "svg",
              "turnstile"
            ]
          },
          "turnstileSiteKey": {
            "type": "string"
          },
          "turnstileSecretKey": {
            "type": "string",
            "description": "Write-only - never returned. Encrypted at rest."
          },
          "turnstileTheme": {
            "type": "string",
            "enum": [
              "light",
              "dark",
              "auto"
            ]
          },
          "turnstileSize": {
            "type": "string",
            "enum": [
              "normal",
              "compact",
              "flexible"
            ]
          },
          "turnstileAppearance": {
            "type": "string",
            "enum": [
              "always",
              "execute",
              "interaction-only"
            ]
          },
          "emailPlaceholder": {
            "type": "string"
          },
          "captchaPlaceholder": {
            "type": "string"
          },
          "formFontStyle": {
            "type": "string"
          },
          "formFontColor": {
            "type": "string"
          },
          "formFontSize": {
            "type": "string"
          },
          "btnLabel": {
            "type": "string"
          },
          "btnFont": {
            "type": "string"
          },
          "btnFontColor": {
            "type": "string"
          },
          "btnColor": {
            "type": "string"
          },
          "btnFontSize": {
            "type": "string"
          },
          "successMessage": {
            "type": "string"
          },
          "successFont": {
            "type": "string"
          },
          "successFontColor": {
            "type": "string"
          },
          "successFontSize": {
            "type": "string"
          },
          "redirectLink": {
            "type": "string"
          },
          "termsAndConditions": {
            "type": "object",
            "properties": {
              "show": {
                "type": "boolean"
              },
              "label": {
                "type": "string"
              },
              "linkLabel": {
                "type": "string"
              },
              "link": {
                "type": "string"
              }
            }
          },
          "propertiesStyle": {
            "type": "object"
          },
          "doubleOptIn": {
            "type": "object",
            "description": "Replaces the whole object when given - to change just one field, GET the current value first and send all five back together. Do not include the GET response's doubleOptIn._id - it is Mongoose's own subdocument id, not a real field, and PATCH rejects it as unexpected.",
            "properties": {
              "active": {
                "type": "boolean"
              },
              "redirectLink": {
                "type": "string"
              },
              "emailId": {
                "type": "string"
              },
              "confirmationTitle": {
                "type": "string"
              },
              "confirmationMessage": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "responses": {
      "ValidationError": {
        "description": "Invalid request body or query - every violation found (missing/invalid/unexpected fields) is reported in one response, semicolon-separated, not just the first one hit.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "integer",
                  "example": 400
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "example": {
              "status": 400,
              "error": {
                "name": "VALIDATION_ERROR",
                "message": "Missing required field: name; Missing required field: subject"
              }
            }
          }
        }
      },
      "AuthError": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "integer",
                  "example": 403
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "example": {
              "status": 403,
              "error": {
                "name": "AUTHORIZATION_ERROR",
                "message": "Permission denied."
              }
            }
          }
        }
      },
      "MethodNotAllowedError": {
        "description": "The operation is blocked by a business rule (e.g. the resource is still in use)",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "integer",
                  "example": 405
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "example": {
              "status": 405,
              "error": {
                "name": "METHOD_NOT_ALLOWED_ERROR",
                "message": "Removing the subscriber list is not allowed because the following emails and automations rely on it: Welcome Email"
              }
            }
          }
        }
      },
      "ConflictError": {
        "description": "The resource already exists",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "integer",
                  "example": 409
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "example": {
              "status": 409,
              "error": {
                "name": "CONFLICT_ERROR",
                "message": "This email is already in the suppression list."
              }
            }
          }
        }
      }
    }
  }
}