{
  "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"
    },
    {
      "name": "Gallery"
    }
  ],
  "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. Two special keys narrow by segment conditions (AND-ed with each other and the rest of the filter): filter[segmentId]=<saved segment id>, and filter[segment]=<JSON {\"groups\": [...]}> with the same groups/conditions shape as a segment (e.g. has-tag, equals on a custom field, engagement). filter[subscriberListId]=<id> keeps only contacts on that subscriber list, optionally with filter[subscriberStatus]=active|unsubscribed|paused|unverified."
          },
          {
            "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. Two special keys narrow by segment conditions (AND-ed with each other and the rest of the filter): filter[segmentId]=<saved segment id>, and filter[segment]=<JSON {\"groups\": [...]}> with the same groups/conditions shape as a segment (e.g. has-tag, equals on a custom field, engagement). filter[subscriberListId]=<id> keeps only contacts on that subscriber list, optionally with filter[subscriberStatus]=active|unsubscribed|paused|unverified."
          },
          {
            "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. Auth: API key, or a whitelisted Origin (in which case a CAPTCHA is required unless the list disables it).\n\nDouble opt-in: when it is on for the list and the request uses an API key (or a whitelisted Origin), a new contact - or one who is unverified or unsubscribed on the list - is not activated. They get the verification email and stay as they are (new contacts become \"unverified\") until they click its link, and the response is { success: true, info } instead of the subscriber. Sending status \"active\" does not skip this. A paused subscriber is reactivated directly, without an email. With a SubscriptionToken the subscriber has already proven they own the address, so they are activated directly.",
        "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.\n\nDouble opt-in: when it is on for the list and the request uses an API key, setting status to \"active\" on an unverified or unsubscribed subscriber does not activate them - they keep their status, get the verification email, and the response includes verificationEmailSent: true. They become active only by clicking its link. A paused subscriber is reactivated directly. With a SubscriptionToken the change applies directly.",
        "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/slug/{slug}": {
      "get": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "Look up a published, BlueFox-hosted signup form by its public slug",
        "description": "Not API-key authenticated - requires a whitelisted Origin header instead, restricted to BlueFox's own app domain (the APP_URL this deployment is configured with) since this endpoint only ever backs the bluefox.email/signup/{slug} page and takes no project-level whitelist. Only returns forms with published: true (404 otherwise, including for a valid slug on an unpublished form). Returns the same self-contained, ready-to-render HTML (styling, markup, and captcha/submit JS included) as GET .../signup-forms/{id}/embed - never the raw form config, so there is no secret-leak surface. Also includes the owning project's name and logoUrl for page branding.",
        "parameters": [
          {
            "name": "slug",
            "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": {
                        "name": {
                          "type": "string"
                        },
                        "pageHeadline": {
                          "type": "string",
                          "description": "The heading to show on the hosted page. Falls back to the project name when not set."
                        },
                        "pageDescription": {
                          "type": "string",
                          "description": "The description to show under the heading on the hosted page."
                        },
                        "formLayout": {
                          "type": "string",
                          "description": "The form's layout (\"row\" or \"column\") - the hosted page uses this to size its own container appropriately, since a row-laid-out form needs more width than a column one."
                        },
                        "html": {
                          "type": "string"
                        },
                        "project": {
                          "type": "object",
                          "properties": {
                            "name": {
                              "type": "string"
                            },
                            "logoUrl": {
                              "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."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/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 (BlueFox's own hosted-page domain is always allowed), and (depending on the form config) a CAPTCHA. Subscribes the contact to every list configured on the form.\n\nDouble opt-in follows the form's own setting, not the lists': when it is on, lists where the contact is new, unverified or unsubscribed get one verification email covering all of them (response { success: true, info }, statuses unchanged until the link is clicked); lists where they are paused are reactivated directly; lists where they are already active are skipped, and if that is every list the request fails with 400 \"Email already exists.\".",
        "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. Status \"scheduled\" requires a valid, parseable scheduledTo (a 400 otherwise), plus the project having usable sending credentials and enough account credit for the recipient count; missing any of these 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}/automations": {
      "get": {
        "tags": [
          "Automations"
        ],
        "summary": "List automations",
        "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/Automation"
                          }
                        },
                        "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": [
          "Automations"
        ],
        "summary": "Create a automation",
        "description": "Either provide trigger directly, or basedOn to duplicate an existing automation. The automation always starts in \"draft\" status - use POST .../automations/{id}/activate once its trigger and sequence are ready.",
        "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/AutomationInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Automation"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{id}": {
      "get": {
        "tags": [
          "Automations"
        ],
        "summary": "Get a single automation",
        "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/Automation"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automations 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": "Automations not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Automations"
        ],
        "summary": "Delete a automation",
        "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"
            }
          },
          {
            "name": "confirm",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            },
            "description": "Must be exactly \"true\" to actually delete. Omit it to get back the automation's current full state with confirmationRequired: true instead, with nothing deleted. A query param rather than a body field, since DELETE requests can't reliably carry a body through every proxy/gateway in between. Always fetch and show the caller (or end user) that state before confirming."
          }
        ],
        "responses": {
          "200": {
            "description": "OK - check result.confirmationRequired before assuming the automation was actually deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/Automation"
                        },
                        {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/Automation"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "confirmationRequired": {
                                  "type": "boolean",
                                  "example": true
                                }
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automations 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": "Automations not found."
                  }
                }
              }
            }
          }
        },
        "description": "This also deletes the automation's email content and running-contact history, and cannot be undone."
      },
      "patch": {
        "tags": [
          "Automations"
        ],
        "summary": "Rename an automation",
        "description": "Only the name can be changed here. trigger, exitCriteria, sequence, and status all have their own dedicated endpoints (node sub-resource, lifecycle actions) so validation and draft-staging always apply.",
        "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": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Automation"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/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. Pass interval + metric for an hourly/daily/weekly/monthly breakdown instead of totals.",
        "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."
          },
          {
            "name": "interval",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hourly",
                "daily",
                "weekly",
                "monthly"
              ]
            },
            "description": "Returns an EmailStatsTimeline (per-period breakdown, same as the app's stats chart) instead of totals. Requires metric. With interval, from/to are rounded to whole UTC days and default to the last 7 days (hourly) or the last month (others). Max range: hourly 7 days, daily 60 days, weekly/monthly 12 months (405 when exceeded)."
          },
          {
            "name": "metric",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sent",
                "failed",
                "opens",
                "uniqueOpens",
                "clicks",
                "uniqueClicks",
                "clicksPerUniqueOpens",
                "uniqueClicksPerUniqueOpens",
                "unsubscribePerUniqueOpens",
                "bounces",
                "complaints",
                "subscribe",
                "unsubscribe",
                "resubscribe",
                "pause-subscription",
                "unpause-subscription"
              ]
            },
            "description": "With interval: what to count per period. subscribe/unsubscribe/resubscribe/pause-subscription/unpause-subscription count subscription changes caused by this email."
          },
          {
            "name": "timeZone",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "Europe/Budapest"
            },
            "description": "With interval: IANA time zone the periods are labelled in. Defaults to UTC."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/EmailStats"
                        },
                        {
                          "$ref": "#/components/schemas/EmailStatsTimeline"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "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."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/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. Pass interval + metric for an hourly/daily/weekly/monthly breakdown instead of totals.",
        "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."
          },
          {
            "name": "interval",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hourly",
                "daily",
                "weekly",
                "monthly"
              ]
            },
            "description": "Returns an EmailStatsTimeline (per-period breakdown, same as the app's stats chart) instead of totals. Requires metric. With interval, from/to are rounded to whole UTC days and default to the last 7 days (hourly) or the last month (others). Max range: hourly 7 days, daily 60 days, weekly/monthly 12 months (405 when exceeded)."
          },
          {
            "name": "metric",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sent",
                "failed",
                "opens",
                "uniqueOpens",
                "clicks",
                "uniqueClicks",
                "clicksPerUniqueOpens",
                "uniqueClicksPerUniqueOpens",
                "bounces",
                "complaints",
                "subscribe",
                "unsubscribe",
                "resubscribe",
                "pause-subscription",
                "unpause-subscription"
              ]
            },
            "description": "With interval: what to count per period. subscribe/unsubscribe/resubscribe/pause-subscription/unpause-subscription count subscription changes caused by this email."
          },
          {
            "name": "timeZone",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "Europe/Budapest"
            },
            "description": "With interval: IANA time zone the periods are labelled in. Defaults to UTC."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/EmailStats"
                        },
                        {
                          "$ref": "#/components/schemas/EmailStatsTimeline"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "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."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/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. Pass interval + metric for an hourly/daily/weekly/monthly breakdown instead of totals.",
        "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."
          },
          {
            "name": "interval",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hourly",
                "daily",
                "weekly",
                "monthly"
              ]
            },
            "description": "Returns an EmailStatsTimeline (per-period breakdown, same as the app's stats chart) instead of totals. Requires metric. With interval, from/to are rounded to whole UTC days and default to the last 7 days (hourly) or the last month (others). Max range: hourly 7 days, daily 60 days, weekly/monthly 12 months (405 when exceeded)."
          },
          {
            "name": "metric",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sent",
                "failed",
                "opens",
                "uniqueOpens",
                "clicks",
                "uniqueClicks",
                "clicksPerUniqueOpens",
                "uniqueClicksPerUniqueOpens",
                "unsubscribePerUniqueOpens",
                "bounces",
                "complaints",
                "subscribe",
                "unsubscribe",
                "resubscribe",
                "pause-subscription",
                "unpause-subscription"
              ]
            },
            "description": "With interval: what to count per period. subscribe/unsubscribe/resubscribe/pause-subscription/unpause-subscription count subscription changes caused by this email."
          },
          {
            "name": "timeZone",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "Europe/Budapest"
            },
            "description": "With interval: IANA time zone the periods are labelled in. Defaults to UTC."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/EmailStats"
                        },
                        {
                          "$ref": "#/components/schemas/EmailStatsTimeline"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "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."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/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). Creates the \ncontact if it doesn't exist yet. Accepts a SubscriptionToken in place of an api key - see that security scheme's \ndescription for how a custom subscription-preferences page uses this to let a subscriber re-join a list they had left.\n\nDouble opt-in: when it is on for the list and the request uses an API key (or a whitelisted Origin), a new contact - or one who is unverified or unsubscribed on the list - is not activated. They get the verification email and stay as they are (new contacts become \"unverified\") until they click its link, and the response is { success: true, info } instead of the subscriber. Sending status \"active\" does not skip this. A paused subscriber is reactivated directly, without an email. With a SubscriptionToken the subscriber has already proven they own the address, so they are activated directly.",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "SubscriptionToken": []
          }
        ],
        "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}/import": {
      "post": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "Import contacts into a list",
        "description": "Bulk-adds up to 1000 contacts to a list in one call, like the app's CSV import. Double opt-in is skipped: contacts \nnot yet on the list are added as \"active\" and no verification email is sent, so only import contacts who already \nagreed to receive your emails. Contacts already on the list (with any status, including \"unsubscribed\") are left \nuntouched and counted in alreadyOnList. Each row creates the contact if it doesn't exist yet, or updates its fields \n(name, tags, custom fields) if it does. A row that fails (invalid, suppressed, or disposable email) is reported in \nerrors and does not stop the rest. API key only - a SubscriptionToken is not accepted.",
        "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": [
                  "contacts"
                ],
                "properties": {
                  "contacts": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 1000,
                    "items": {
                      "type": "object",
                      "required": [
                        "email"
                      ],
                      "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": {
                      "type": "object",
                      "properties": {
                        "imported": {
                          "type": "integer",
                          "description": "Contacts added to the list as active."
                        },
                        "alreadyOnList": {
                          "type": "integer",
                          "description": "Contacts already on the list, left untouched."
                        },
                        "errors": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "email": {
                                "type": "string"
                              },
                              "message": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "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."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/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). Accepts a SubscriptionToken \nin place of an api key - see that security scheme's description for how a custom subscription-preferences page \nuses this to let a subscriber pause or unsubscribe.\n\nDouble opt-in: when it is on for the list and the request uses an API key, setting status to \"active\" on an unverified or unsubscribed subscriber does not activate them - they keep their status, get the verification email, and the response includes verificationEmailSent: true. They become active only by clicking its link. A paused subscriber is reactivated directly. With a SubscriptionToken the change applies directly.",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "SubscriptionToken": []
          }
        ],
        "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}/subscriber-lists/public/{email}": {
      "get": {
        "tags": [
          "Subscriber Lists"
        ],
        "summary": "List every subscriber list an email can manage, with its current status on each",
        "description": "The endpoint behind a subscriber-facing subscription-preferences page: every public list in the project, plus - \nif authenticating with a SubscriptionToken minted for one - the single private list it names, each carrying this \nemail's current status (active/paused/unsubscribed) where a subscription exists. Building a custom preferences \npage for this project? See the SubscriptionToken security scheme below for the full flow: take the `token` query \nparameter off the unsubscribe/pause-subscription link, call this endpoint with it to render the page, then \nPATCH/POST the individual subscriber-lists endpoints (same token) as the subscriber makes changes.",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "SubscriptionToken": []
          }
        ],
        "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": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "_id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "description": {
                                "type": "string"
                              },
                              "private": {
                                "type": "boolean"
                              },
                              "subscriber": {
                                "type": "object",
                                "description": "Present only when this email has a subscription (of any status) on this list.",
                                "properties": {
                                  "email": {
                                    "type": "string"
                                  },
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "unverified",
                                      "active",
                                      "unsubscribed",
                                      "paused"
                                    ]
                                  },
                                  "pausedUntil": {
                                    "type": "string",
                                    "format": "date-time"
                                  }
                                },
                                "additionalProperties": true
                              }
                            },
                            "additionalProperties": true
                          }
                        },
                        "count": {
                          "type": "integer"
                        },
                        "logoUrl": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Contact, or there are no available 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": "Contact, or there are no available subscriber lists not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/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."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{automationId}/trigger": {
      "patch": {
        "tags": [
          "Automations"
        ],
        "summary": "Set an automation's trigger",
        "description": "While the automation is \"draft\", writes the live trigger directly. Once active/paused, stages it as draftTrigger instead - it only takes effect after POST .../merge-draft. Not validated at set-time (shape/business-rule validation happens at activate/merge-draft).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "A full trigger object, discriminated by type - replaces whatever trigger (or draftTrigger) shape was there before."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Automation"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{automationId}/exit-criteria": {
      "patch": {
        "tags": [
          "Automations"
        ],
        "summary": "Set an automation's exit criteria",
        "description": "Same draft/live routing as the trigger endpoint above. Pass { active: false } to clear 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": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "A full exit-criteria object - replaces whatever exitCriteria (or draftExitCriteria) shape was there before."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Automation"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{automationId}/node": {
      "post": {
        "tags": [
          "Automations"
        ],
        "summary": "Add a sequence node to an automation",
        "description": "While the automation is \"draft\", inserts directly into the live sequence. While \"active\" or \"paused\", the node is inserted into (a copy of) the sequence staged as draftSequence instead, leaving the running automation untouched until POST .../merge-draft.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AutomationNodeInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Automation"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{automationId}/node/{id}": {
      "put": {
        "tags": [
          "Automations"
        ],
        "summary": "Update a sequence node",
        "description": "Same draft/live routing as adding a node - see POST .../node.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The node's _id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AutomationNodeInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Automation"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Node 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": "Node not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Automations"
        ],
        "summary": "Delete a sequence node",
        "description": "A send-email/notify node whose email content already exists is only marked deleted on the staged draft (so a merge can still remove it) rather than being spliced out immediately, when the automation is active/paused. Same draft/live routing as adding a node otherwise.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The node's _id."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/Automation"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Node 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": "Node not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{automationId}/email": {
      "get": {
        "tags": [
          "Automations"
        ],
        "summary": "List the email content documents belonging to an automation",
        "description": "One item per send-email/notify node that has been given content. Pass filter[nodeId]=<node _id> to instead get only the emails that run at or before that node in the sequence (useful for showing \"what has this contact already received by this point\").",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "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": [
                "createdAt",
                "updatedAt"
              ],
              "default": "createdAt"
            },
            "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/AutomationEmailContent"
                          }
                        },
                        "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}/automations/{automationId}/email/{id}": {
      "get": {
        "tags": [
          "Automations"
        ],
        "summary": "Get a single send-email/notify node's email content",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "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/AutomationEmailContent"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "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": "Email not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Automations"
        ],
        "summary": "Update a send-email/notify node's email content",
        "description": "Merges the given fields into the existing content. Same draft/live routing as node edits - while the automation is active/paused this is staged and has no effect until POST .../merge-draft.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AutomationEmailContentInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/AutomationEmailContent"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "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": "Email not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{id}/activate": {
      "post": {
        "tags": [
          "Automations"
        ],
        "summary": "Activate a draft automation",
        "description": "Validates the trigger and the full sequence (every node's required fields, branch conditions, and any send-email/notify node's referenced email content) before doing anything. If validation fails, nothing is changed and the response has hasErrors: true with each problem node's error array populated - fix and call again. On success the automation becomes \"active\" and starts running for matching contacts. Requires { \"confirm\": true } in the body - omit it (or send false) to get back the automation's current full state with confirmationRequired: true instead, with nothing applied. Always fetch and show the caller (or end user) that state before sending confirm: true.",
        "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": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm": {
                    "type": "boolean",
                    "default": false,
                    "description": "Must be true to actually apply this action."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - check result.hasErrors/result.confirmationRequired before assuming the action actually applied.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/Automation"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "hasErrors": {
                              "type": "boolean",
                              "example": true
                            }
                          }
                        },
                        {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/Automation"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "confirmationRequired": {
                                  "type": "boolean",
                                  "example": true
                                }
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{id}/merge-draft": {
      "post": {
        "tags": [
          "Automations"
        ],
        "summary": "Merge staged draft changes into a live automation",
        "description": "Only meaningful when status is \"active\" or \"paused\" and draftSequence/draftTrigger/draftExitCriteria are present (i.e. node/trigger/exit-criteria edits were made after the automation went live). Re-validates the same way as activate and is a no-op (hasErrors: true, nothing persisted) on failure. On success, the staged draft becomes the live sequence/trigger/exitCriteria and any contact currently mid-automation is transitioned onto the new sequence from its current position. Requires { \"confirm\": true } in the body - omit it (or send false) to get back the automation's current full state with confirmationRequired: true instead, with nothing applied. Always fetch and show the caller (or end user) that state before sending confirm: true.",
        "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": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm": {
                    "type": "boolean",
                    "default": false,
                    "description": "Must be true to actually apply this action."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - check result.hasErrors/result.confirmationRequired before assuming the action actually applied.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/Automation"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "hasErrors": {
                              "type": "boolean",
                              "example": true
                            }
                          }
                        },
                        {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/Automation"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "confirmationRequired": {
                                  "type": "boolean",
                                  "example": true
                                }
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{id}/discard-draft": {
      "post": {
        "tags": [
          "Automations"
        ],
        "summary": "Discard staged draft changes",
        "description": "Drops draftSequence/draftTrigger/draftExitCriteria without touching the live, running automation - use when staged edits turned out to be wrong. Not validated (there is nothing to validate away). Requires { \"confirm\": true } in the body - omit it (or send false) to get back the automation's current full state with confirmationRequired: true instead, with nothing applied. Always fetch and show the caller (or end user) that state before sending confirm: true.",
        "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": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm": {
                    "type": "boolean",
                    "default": false,
                    "description": "Must be true to actually apply this action."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - check result.hasErrors/result.confirmationRequired before assuming the action actually applied.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/Automation"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "hasErrors": {
                              "type": "boolean",
                              "example": true
                            }
                          }
                        },
                        {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/Automation"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "confirmationRequired": {
                                  "type": "boolean",
                                  "example": true
                                }
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{id}/pause": {
      "post": {
        "tags": [
          "Automations"
        ],
        "summary": "Pause a live automation",
        "description": "Stops the automation from processing further steps for any contact, and stops new contacts from entering it, without discarding its configuration - resume to continue exactly where it left off. Requires { \"confirm\": true } in the body - omit it (or send false) to get back the automation's current full state with confirmationRequired: true instead, with nothing applied. Always fetch and show the caller (or end user) that state before sending confirm: true.",
        "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": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm": {
                    "type": "boolean",
                    "default": false,
                    "description": "Must be true to actually apply this action."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - check result.hasErrors/result.confirmationRequired before assuming the action actually applied.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/Automation"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "hasErrors": {
                              "type": "boolean",
                              "example": true
                            }
                          }
                        },
                        {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/Automation"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "confirmationRequired": {
                                  "type": "boolean",
                                  "example": true
                                }
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{id}/resume": {
      "post": {
        "tags": [
          "Automations"
        ],
        "summary": "Resume a paused automation",
        "description": "Re-validates the same way as activate (a paused automation's configuration may have been edited while paused) and is a no-op on failure. Requires { \"confirm\": true } in the body - omit it (or send false) to get back the automation's current full state with confirmationRequired: true instead, with nothing applied. Always fetch and show the caller (or end user) that state before sending confirm: true.",
        "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": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm": {
                    "type": "boolean",
                    "default": false,
                    "description": "Must be true to actually apply this action."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - check result.hasErrors/result.confirmationRequired before assuming the action actually applied.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/Automation"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "hasErrors": {
                              "type": "boolean",
                              "example": true
                            }
                          }
                        },
                        {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/Automation"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "confirmationRequired": {
                                  "type": "boolean",
                                  "example": true
                                }
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{id}/running-nodes": {
      "get": {
        "tags": [
          "Automations"
        ],
        "summary": "Count currently running/waiting contacts per node",
        "description": "One entry per node _id currently occupied by at least one contact, e.g. { \"<nodeId>\": 3 }. Only counts contacts with status \"running\" or \"paused\" (waiting at a delay node until its pauseUntil time; not completed/errored). Contacts enrolled but not yet at any node are counted under the key \"undefined\" - list them with currentNodeId \"trigger\". Use GET .../running-nodes/{currentNodeId} to list the actual contacts at one node.",
        "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 automation's _id."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "integer"
                      },
                      "example": {
                        "671f1a2b3c4d5e6f70819293": 3
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{automationId}/running-nodes/{currentNodeId}": {
      "get": {
        "tags": [
          "Automations"
        ],
        "summary": "List the contacts currently at one node",
        "description": "Only contacts with status \"running\" or \"paused\" (\"paused\" means waiting at a delay node - pauseUntil says when it continues). Pass \"trigger\" as currentNodeId (instead of a real node _id) to list contacts who have been enrolled but haven't reached the first node yet.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "currentNodeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "A node _id from the automation's sequence, or the literal string \"trigger\"."
          },
          {
            "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."
          }
        ],
        "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": {
                              "_id": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "running",
                                  "paused"
                                ],
                                "description": "\"paused\" means waiting at a delay node, not stuck."
                              },
                              "pauseUntil": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When a paused contact continues to the next node (UTC). Only set while paused."
                              },
                              "currentIndex": {
                                "type": "integer"
                              },
                              "contactId": {
                                "type": "object",
                                "description": "Populated contact document, not just an id."
                              }
                            }
                          }
                        },
                        "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": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{id}/stats": {
      "get": {
        "tags": [
          "Automations"
        ],
        "summary": "Get stats for an automation",
        "description": "How many contacts have gone through it (active/completed/errored) plus opens/clicks/sends/bounces/complaints for each of its emails and summed across them. The optional from/to range only applies to the email stats.",
        "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 automation's _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/AutomationStats"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Automation 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": "Automation not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{automationId}/email/{id}/stats": {
      "get": {
        "tags": [
          "Automations"
        ],
        "summary": "Get stats for one automation email",
        "description": "Same counts as the other email stats endpoints, for the email sent by one send-email/notify node. Pass interval + metric for an hourly/daily/weekly/monthly breakdown instead of totals. For who received/opened/clicked it, see GET .../email/{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": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The automation email _id (the node's emailId)."
          },
          {
            "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."
          },
          {
            "name": "interval",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hourly",
                "daily",
                "weekly",
                "monthly"
              ]
            },
            "description": "Returns an EmailStatsTimeline (per-period breakdown, same as the app's stats chart) instead of totals. Requires metric. With interval, from/to are rounded to whole UTC days and default to the last 7 days (hourly) or the last month (others). Max range: hourly 7 days, daily 60 days, weekly/monthly 12 months (405 when exceeded)."
          },
          {
            "name": "metric",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sent",
                "failed",
                "opens",
                "uniqueOpens",
                "clicks",
                "uniqueClicks",
                "clicksPerUniqueOpens",
                "uniqueClicksPerUniqueOpens",
                "unsubscribePerUniqueOpens",
                "bounces",
                "complaints",
                "subscribe",
                "unsubscribe",
                "resubscribe",
                "pause-subscription",
                "unpause-subscription"
              ]
            },
            "description": "With interval: what to count per period. subscribe/unsubscribe/resubscribe/pause-subscription/unpause-subscription count subscription changes caused by this email."
          },
          {
            "name": "timeZone",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "Europe/Budapest"
            },
            "description": "With interval: IANA time zone the periods are labelled in. Defaults to UTC."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/EmailStats"
                        },
                        {
                          "$ref": "#/components/schemas/EmailStatsTimeline"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "AutomationEmail 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": "AutomationEmail not found."
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowedError"
          }
        }
      }
    },
    "/v1/projectId/{projectId}/automations/{automationId}/email/{id}/recipients": {
      "get": {
        "tags": [
          "Automations"
        ],
        "summary": "List recipients of one automation 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": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The automation email _id (the node's emailId)."
          },
          {
            "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": "AutomationEmail 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": "AutomationEmail not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/gallery/folders": {
      "get": {
        "tags": [
          "Gallery"
        ],
        "summary": "List gallery folders",
        "description": "Lists the folders directly inside a given folder. By default (parentFolderId omitted) this is the top level of the gallery as this project sees it: this project's own top-level folders, PLUS any account-wide shared folder (one with no project of its own, e.g. \"Company Logos\" - visible to and usable from every project in the account). The project's own top level has no folder entry of its own - the response's galleryName field carries its name (the project name). Pass parentFolderId to list a subfolder's contents instead, which can be inside either your own tree or a shared one - but never inside a different project's own private tree.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "parentFolderId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "A folder _id to list the children of. Omit to list the top-level folders."
          },
          {
            "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/GalleryFolder"
                          }
                        },
                        "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."
                        },
                        "galleryName": {
                          "type": "string",
                          "description": "The name of this project's own gallery space (kept in sync with the project name). The project's top level has no folder entry of its own, so this is how a caller knows which gallery the listing belongs to."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Parent folder 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": "Parent folder not found."
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Gallery"
        ],
        "summary": "Create a gallery folder",
        "description": "Defaults to creating the folder at the top level of this project's own tree. Pass parentFolderId (your own or an account-wide shared folder's id) to nest it there 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": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GalleryFolderInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/GalleryFolder"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Parent folder 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": "Parent folder not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/gallery/folders/{id}": {
      "get": {
        "tags": [
          "Gallery"
        ],
        "summary": "Get a single gallery folder",
        "description": "Works for a folder anywhere in this project's own tree, or in an account-wide shared tree. 404s for a folder that belongs to a different project's own (non-shared) tree.",
        "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/GalleryFolder"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Folder 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": "Folder not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Gallery"
        ],
        "summary": "Rename a gallery folder",
        "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": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/GalleryFolder"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Folder 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": "Folder not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Gallery"
        ],
        "summary": "Delete a gallery folder",
        "description": "Recursively deletes every subfolder and image nested inside it too (including their files in storage) - there is no separate confirmation step, this cannot be undone.",
        "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/GalleryFolder"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Folder 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": "Folder not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/gallery/images": {
      "get": {
        "tags": [
          "Gallery"
        ],
        "summary": "List gallery images",
        "description": "Lists the images directly inside a given folder - by default the top level of this project's own gallery (whose name is in the response's galleryName field). Pass parentFolderId to list a subfolder's contents instead.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The project _id, found in the app under Project Settings."
          },
          {
            "name": "parentFolderId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "A folder _id to list the images inside. Omit to list the top-level images."
          },
          {
            "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/GalleryImage"
                          }
                        },
                        "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."
                        },
                        "galleryName": {
                          "type": "string",
                          "description": "The name of this project's own gallery space (kept in sync with the project name). The project's top level has no folder entry of its own, so this is how a caller knows which gallery the listing belongs to."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Parent folder 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": "Parent folder not found."
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Gallery"
        ],
        "summary": "Upload a gallery image",
        "description": "A multipart/form-data upload (not JSON like other create endpoints, since it carries a binary file). Allowed types: image/jpeg, image/png, image/gif - any other type 400s.",
        "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": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "image"
                ],
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary",
                    "description": "The image file (jpeg/png/gif)."
                  },
                  "name": {
                    "type": "string",
                    "description": "Defaults to the uploaded file's own filename when omitted."
                  },
                  "parentFolderId": {
                    "type": "string",
                    "description": "An existing folder _id to upload into. Omit to upload to the top level of the project's gallery."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/GalleryImage"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Parent folder 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": "Parent folder not found."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projectId/{projectId}/gallery/images/{id}": {
      "get": {
        "tags": [
          "Gallery"
        ],
        "summary": "Get a single gallery image",
        "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/GalleryImage"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Image 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": "Image not found."
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Gallery"
        ],
        "summary": "Rename a gallery image",
        "description": "Renames the image record only - does not replace the uploaded file itself. Upload a new image and delete the old one to replace the file.",
        "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": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 200
                    },
                    "result": {
                      "$ref": "#/components/schemas/GalleryImage"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Image 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": "Image not found."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Gallery"
        ],
        "summary": "Delete a gallery image",
        "description": "Also deletes the underlying file in storage - this cannot be undone.",
        "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/GalleryImage"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/AuthError"
          },
          "404": {
            "description": "Image 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": "Image 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."
      },
      "SubscriptionToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "ONLY valid on the specific subscriber-list endpoints that list it as an alternative to ApiKeyAuth - not a general-purpose credential.\nThis is the `token` query-string parameter bluefox.email appends to the unsubscribe/pause-subscription link in every email \n(`https://your-domain.example/preferences?token=...` once a customSubscriptionPreferencesUrl is set on the project, see \nPATCH /v1/projectId/{projectId} - otherwise it points at bluefox.email's own default page). If you are building a custom \nsubscription-preferences page for a project, that page never needs and should never hold the project's API key - the token \nis the only credential it sees, and everything the page needs comes out of it:\n\n1. The link gives ONLY the token, not a projectId or email - read those out of the token itself. It is a standard three-part \n   JWT (header.payload.signature): base64url-decode the middle (payload) segment and JSON-parse it to get `projectId`, \n   `email`, and `type` (\"unsubscribe\" or \"pause-subscription\"). No verification needed client-side, this is just reading \n   data - never decode the header/signature or construct/modify a token; always send the raw string back exactly as received.\n2. With projectId and email in hand, GET /v1/projectId/{projectId}/subscriber-lists/public/{email} - `Authorization: Bearer \n   <the raw token>` - to render the page. Response shape: { result: { items: [{ _id, name, description, private, \n   subscriber: { status, pausedUntil, email, name, ... } }], count, logoUrl } }. `subscriber` is present only on lists this \n   email has ever subscribed to (any status) - omitted means \"not subscribed, offer to join\". `status` is one of \n   \"unverified\" | \"active\" | \"unsubscribed\" | \"paused\"; `pausedUntil` (ISO date) only matters when status is \"paused\".\n3. To change one list, same bearer token: PATCH .../subscriber-lists/{id}/subscribers/{email} with { status } - \"active\" \n   (resubscribe), \"unsubscribed\", or \"paused\" (also requires a future-dated `pausedUntil`). To join a list this email is not \n   on at all, POST .../subscriber-lists/{id}/subscribers with { email, status: \"active\" } (the email must match the token's).\n4. Scope: the token authorizes its email on every PUBLIC list in the project across all three calls - a PRIVATE list is only \n   reachable when the token's own payload names that exact list as `subscriberListId` (true only for links generated from an \n   email sent to that one private list). GET silently omits private lists the token cannot access; PATCH/POST on one 403.\n\nSame token for every call on that page load - never persist it, generate one, or reuse it beyond that session."
      }
    },
    "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"
          },
          "webVersionEnabled": {
            "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\". Stored with the campaign and shown next to the scheduled time in the app; it does not shift scheduledTo, which must be an absolute instant."
          },
          "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 a valid scheduledTo to schedule sending. Status \"scheduled\" without a parseable scheduledTo is rejected with a 400."
          },
          "scheduledTo": {
            "type": "string",
            "format": "date-time",
            "description": "Absolute ISO 8601 date-time (with a UTC offset or trailing \"Z\"). Required when status is \"scheduled\"."
          },
          "excludeUnengaged": {
            "type": "boolean"
          },
          "webVersionEnabled": {
            "type": "boolean",
            "description": "Turns on the public web version (\"view in browser\" page) of the campaign. Defaults to false. The page only works while this is true and the status is \"sent\" or \"archive\"."
          },
          "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. Contact data is ONLY available under the `contact.` prefix - bare tags like `{{name}}`, `{{firstName}}` or `{{email}}` render as empty strings. For a fallback use DEFAULT, e.g. `Hi {{DEFAULT contact.name \"there\"}},`.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - `{{webVersionLink}}` - campaigns only: a public \"view in browser\" link to the campaign (the same link for every recipient, also shown on the campaign card in the app). It is not personalized - contact merge tags show their DEFAULT fallback. It only works while the campaign's webVersionEnabled is true and its status is \"sent\" or \"archive\" (when adding this tag, also set webVersionEnabled: true), and always shows the latest version of the campaign (edits made after sending are visible to earlier recipients).\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. Contact data is ONLY available under the `contact.` prefix - bare tags like `{{name}}`, `{{firstName}}` or `{{email}}` render as empty strings. For a fallback use DEFAULT, e.g. `Hi {{DEFAULT contact.name \"there\"}},`.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - `{{webVersionLink}}` - campaigns only: a public \"view in browser\" link to the campaign (the same link for every recipient, also shown on the campaign card in the app). It is not personalized - contact merge tags show their DEFAULT fallback. It only works while the campaign's webVersionEnabled is true and its status is \"sent\" or \"archive\" (when adding this tag, also set webVersionEnabled: true), and always shows the latest version of the campaign (edits made after sending are visible to earlier recipients).\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. Contact data is ONLY available under the `contact.` prefix - bare tags like `{{name}}`, `{{firstName}}` or `{{email}}` render as empty strings. For a fallback use DEFAULT, e.g. `Hi {{DEFAULT contact.name \"there\"}},`.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - `{{webVersionLink}}` - campaigns only: a public \"view in browser\" link to the campaign (the same link for every recipient, also shown on the campaign card in the app). It is not personalized - contact merge tags show their DEFAULT fallback. It only works while the campaign's webVersionEnabled is true and its status is \"sent\" or \"archive\" (when adding this tag, also set webVersionEnabled: true), and always shows the latest version of the campaign (edits made after sending are visible to earlier recipients).\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."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "Automation": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "active",
              "paused"
            ]
          },
          "trigger": {
            "type": "object",
            "description": "Discriminated by trigger.type (contact-added | contact-updated | enter-segment | leave-segment | time-based) - shape varies by type, see the Automations guide. Every type except time-based also supports runOnce (boolean, default true): when true, a contact who has ever run this automation before is skipped even if the trigger matches again; set false to let them re-enter each time it matches."
          },
          "exitCriteria": {
            "type": "object",
            "description": "A condition that removes a contact from this automation mid-flow when true. Has an \"active\" boolean plus condition fields."
          },
          "sequence": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AutomationNode"
            },
            "description": "The live, running sequence. Use the node sub-resource endpoints to add/update/delete nodes rather than replacing this array directly."
          },
          "draftSequence": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AutomationNode"
            },
            "description": "Present only while this automation is active and has unmerged staged edits. POST .../merge-draft to apply, or .../discard-draft to drop them."
          },
          "draftTrigger": {
            "type": "object",
            "description": "Staged trigger edit, present only while active with unmerged changes."
          },
          "draftExitCriteria": {
            "type": "object",
            "description": "Staged exit-criteria edit, present only while active with unmerged changes."
          },
          "usedSegments": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "lastTriggeredAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AutomationInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "trigger": {
            "type": "object",
            "description": "Required on create unless basedOn is given. Shape depends on type - see the Automations guide."
          },
          "exitCriteria": {
            "type": "object"
          },
          "basedOn": {
            "type": "string",
            "description": "Duplicate an existing automation (by _id) as the starting point - copies its sequence, trigger, and exit criteria. The new automation is always created in \"draft\" status regardless of the source's status."
          },
          "subscriberListId": {
            "type": "string",
            "description": "With basedOn, overrides the duplicated trigger's subscriberListId - lets you clone an automation onto a different list."
          }
        }
      },
      "AutomationNode": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "delay",
              "send-email",
              "filter-audience",
              "branch",
              "complete",
              "set-value",
              "notify",
              "manage-tags",
              "webhook"
            ]
          },
          "error": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Populated by the server when this node fails validation on an activate/merge-draft attempt - not settable by the client."
          }
        },
        "description": "Shape varies by type - see the Automations guide for each node type's fields (delay: duration/durationType/waitUntilTime/waitUntilDay - waitUntilDay is an array of day names like [\"monday\", \"thursday\"], the contact waits for whichever comes first, a single string is also accepted; send-email/notify: emailId + subject/previewText/document/senderIdentity/replyTo/feeds; filter-audience: property/operator/value/segmentId/link/excludeUnengaged; branch: branches[] each with a condition (same fields as filter-audience, nested) + its own sequence; set-value: property/value; manage-tags: addValue/removeValue; webhook: url/method/headers/includeContactData). filter-audience/branch-condition operator additionally supports is-opened/is-clicked/is-not-opened/is-not-clicked, which check one specific EMAIL rather than a segment or contact property: set value to that email's emailId (from an earlier send-email/notify node in the same automation - the server rejects any value that isn't one) and, for is-clicked/is-not-clicked, optionally link to narrow to one link within it. property/operator/value/link are ignored whenever segmentId is set instead."
      },
      "AutomationNodeInput": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "delay",
              "send-email",
              "filter-audience",
              "branch",
              "condition",
              "set-value",
              "notify",
              "complete",
              "manage-tags",
              "webhook"
            ],
            "description": "\"condition\" is special: it does not add a top-level node. Instead, set prevNodeId to an EXISTING branch node's own _id, and it appends one more arm to that branch's branches[] (branches start with two). Its condition fields go under a nested \"condition\" object in the body, e.g. { \"type\": \"condition\", \"prevNodeId\": \"<branchNodeId>\", \"condition\": { \"property\": \"...\", \"operator\": \"...\", \"value\": \"...\" } } - not flat on the request body like filter-audience."
          },
          "prevNodeId": {
            "type": "string",
            "description": "Create only. Insert immediately after this node (a sibling _id anywhere in the tree, including inside a branch). Omit to insert as the very first node."
          }
        },
        "description": "Plus whatever type-specific fields that node type needs (see AutomationNode) - on create these are optional and the node starts with sensible defaults; on update at least one field to change is expected."
      },
      "AutomationEmailContent": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "chamaileon",
              "html",
              "text"
            ]
          },
          "document": {
            "description": "Chamaileon JSON if type is \"chamaileon\", otherwise an HTML/text string."
          },
          "senderIdentity": {
            "type": "string"
          },
          "replyTo": {
            "type": "string"
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "AutomationEmailContentInput": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "chamaileon",
              "html",
              "text"
            ]
          },
          "document": {},
          "senderIdentity": {
            "type": "string"
          },
          "replyTo": {
            "type": "string"
          },
          "feeds": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "SignUpForm": {
        "type": "object",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "published": {
            "type": "boolean",
            "description": "When true, the form is reachable at the BlueFox-hosted URL bluefox.email/signup/{slug}."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier used for the BlueFox-hosted signup page."
          },
          "pageHeadline": {
            "type": "string",
            "description": "Shown as the heading on the BlueFox-hosted signup page. Falls back to the project name if not set."
          },
          "pageDescription": {
            "type": "string",
            "description": "Shown under the headline on the BlueFox-hosted signup page."
          },
          "useDefaultTurnstile": {
            "type": "boolean",
            "description": "Defaults to true. When true, the BlueFox-hosted page (not embeds) shows and validates BlueFox's own Turnstile challenge, regardless of captchaType below - which still governs embeds, and governs the hosted page too when this is false."
          },
          "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"
          },
          "published": {
            "type": "boolean",
            "description": "When true, the form is reachable at the BlueFox-hosted URL bluefox.email/signup/{slug}. Requires a slug - either set here or already on the form."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the BlueFox-hosted signup page. Not generated automatically; rejected with a 400 if already taken by another form."
          },
          "pageHeadline": {
            "type": "string",
            "description": "Shown as the heading on the BlueFox-hosted signup page. Falls back to the project name if not set."
          },
          "pageDescription": {
            "type": "string",
            "description": "Shown under the headline on the BlueFox-hosted signup page."
          },
          "useDefaultTurnstile": {
            "type": "boolean",
            "description": "Defaults to true. When true, the BlueFox-hosted page (not embeds) shows and validates BlueFox's own Turnstile challenge, regardless of captchaType below - which still governs embeds, and governs the hosted page too when this is false."
          },
          "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"
          }
        }
      },
      "EmailStatsTimeline": {
        "type": "object",
        "description": "Returned instead of EmailStats when interval/metric are given: the same per-period data as the stats chart in the app.",
        "properties": {
          "interval": {
            "type": "string",
            "enum": [
              "hourly",
              "daily",
              "weekly",
              "monthly"
            ]
          },
          "metric": {
            "type": "string"
          },
          "timeZone": {
            "type": "string",
            "description": "The time zone the periods are labelled in."
          },
          "from": {
            "type": "string",
            "format": "date-time",
            "description": "Start of the range actually used (start of the UTC day)."
          },
          "to": {
            "type": "string",
            "format": "date-time",
            "description": "End of the range actually used (end of the UTC day)."
          },
          "buckets": {
            "type": "array",
            "description": "Only periods with activity are listed - missing periods had 0. When nothing happened at all, a single period with count 0 is returned.",
            "items": {
              "type": "object",
              "properties": {
                "period": {
                  "type": "string",
                  "example": "2026-10-01 10:00",
                  "description": "\"YYYY-MM-DD HH:00\" (hourly), \"YYYY-MM-DD\" (daily), \"YYYY-MM-DD to YYYY-MM-DD\" (weekly) or \"YYYY-MM\" (monthly)."
                },
                "count": {
                  "type": "integer",
                  "description": "Not returned for the *PerUniqueOpens metrics."
                },
                "rate": {
                  "type": "number",
                  "nullable": true,
                  "description": "Count metrics: the count as a percentage of all sends (null when nothing was sent). *PerUniqueOpens metrics: the percentage itself. Not returned for subscription metrics."
                }
              }
            }
          }
        }
      },
      "AutomationStats": {
        "type": "object",
        "description": "Contact counts for the automation (all-time, the from/to range does not apply to them) plus email stats summed across all of its emails and broken down per email.",
        "properties": {
          "contacts": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer",
                "description": "Every run ever started, including completed/errored ones."
              },
              "active": {
                "type": "integer",
                "description": "Currently running or paused (waiting at a timer). See GET .../running-nodes for which step they are at."
              },
              "completed": {
                "type": "integer"
              },
              "error": {
                "type": "integer"
              }
            }
          },
          "totals": {
            "$ref": "#/components/schemas/EmailStats"
          },
          "emails": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "type": "object",
                  "properties": {
                    "emailId": {
                      "type": "string",
                      "description": "Matches the emailId on the send-email/notify node that sends it."
                    },
                    "subject": {
                      "type": "string"
                    }
                  }
                },
                {
                  "$ref": "#/components/schemas/EmailStats"
                }
              ]
            }
          }
        }
      },
      "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"
          },
          "customSubscriptionPreferencesUrl": {
            "type": "string",
            "description": "A subscriber-facing page you host yourself for managing subscription preferences. When set, unsubscribe and pause links in emails point here (with a token query param appended) instead of bluefox.email's default page. Stored and returned with a real http:// or https:// scheme - an explicit one you send is kept exactly as given (e.g. \"http://localhost:3000/preferences\" for local testing), otherwise https is assumed."
          },
          "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."
          },
          "customSubscriptionPreferencesUrl": {
            "type": "string",
            "description": "A subscriber-facing page you host yourself for managing subscription preferences, used instead of bluefox.email's default page. Send with an explicit http:// or https:// scheme to have it kept exactly as given (e.g. \"http://localhost:3000/preferences\" for local testing) - otherwise https is assumed. Pass an empty string to revert to the default page."
          },
          "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."
          }
        }
      },
      "GalleryFolder": {
        "type": "object",
        "description": "Every project gets its own slice of the account-wide media gallery, plus read/write access to any account-wide shared folder (one with no project of its own) - but never another project's own private folders.",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "parentFolderId": {
            "type": "string",
            "nullable": true,
            "description": "The parent folder's _id, or null if this folder is at the top level (either this project's own top level, or an account-wide shared folder itself). The project's own top level is implicit and has no id of its own - it is never returned as a folder, only referenced by omitting parentFolderId. A shared folder, in contrast, is returned as a normal folder with a real id."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GalleryFolderInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "parentFolderId": {
            "type": "string",
            "description": "An existing folder _id to nest the new folder under - either one from this project's own tree, or an account-wide shared folder. Omit to create it at the top level of this project's own tree."
          }
        }
      },
      "GalleryImage": {
        "type": "object",
        "description": "Every project gets its own slice of the account-wide media gallery, plus read/write access to any account-wide shared folder's images - but never another project's own private images.",
        "properties": {
          "_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "parentFolderId": {
            "type": "string",
            "nullable": true,
            "description": "The containing folder's _id, or null if the image is at the top level of this project's gallery."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "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\". Stored with the campaign and shown next to the scheduled time in the app; it does not shift scheduledTo, which must be an absolute instant."
          },
          "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 a valid scheduledTo to schedule sending. Status \"scheduled\" without a parseable scheduledTo is rejected with a 400."
          },
          "scheduledTo": {
            "type": "string",
            "format": "date-time",
            "description": "Absolute ISO 8601 date-time (with a UTC offset or trailing \"Z\"). Required when status is \"scheduled\"."
          },
          "excludeUnengaged": {
            "type": "boolean"
          },
          "webVersionEnabled": {
            "type": "boolean",
            "description": "Turns on the public web version (\"view in browser\" page) of the campaign. Defaults to false. The page only works while this is true and the status is \"sent\" or \"archive\"."
          },
          "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. Contact data is ONLY available under the `contact.` prefix - bare tags like `{{name}}`, `{{firstName}}` or `{{email}}` render as empty strings. For a fallback use DEFAULT, e.g. `Hi {{DEFAULT contact.name \"there\"}},`.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - `{{webVersionLink}}` - campaigns only: a public \"view in browser\" link to the campaign (the same link for every recipient, also shown on the campaign card in the app). It is not personalized - contact merge tags show their DEFAULT fallback. It only works while the campaign's webVersionEnabled is true and its status is \"sent\" or \"archive\" (when adding this tag, also set webVersionEnabled: true), and always shows the latest version of the campaign (edits made after sending are visible to earlier recipients).\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. Contact data is ONLY available under the `contact.` prefix - bare tags like `{{name}}`, `{{firstName}}` or `{{email}}` render as empty strings. For a fallback use DEFAULT, e.g. `Hi {{DEFAULT contact.name \"there\"}},`.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - `{{webVersionLink}}` - campaigns only: a public \"view in browser\" link to the campaign (the same link for every recipient, also shown on the campaign card in the app). It is not personalized - contact merge tags show their DEFAULT fallback. It only works while the campaign's webVersionEnabled is true and its status is \"sent\" or \"archive\" (when adding this tag, also set webVersionEnabled: true), and always shows the latest version of the campaign (edits made after sending are visible to earlier recipients).\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. Contact data is ONLY available under the `contact.` prefix - bare tags like `{{name}}`, `{{firstName}}` or `{{email}}` render as empty strings. For a fallback use DEFAULT, e.g. `Hi {{DEFAULT contact.name \"there\"}},`.\n  - `{{unsubscribeLink}}` and `{{pauseSubscriptionLink}}` - available for campaign/triggered/automation emails (subscriber-list-bound), NOT for transactional emails.\n  - `{{webVersionLink}}` - campaigns only: a public \"view in browser\" link to the campaign (the same link for every recipient, also shown on the campaign card in the app). It is not personalized - contact merge tags show their DEFAULT fallback. It only works while the campaign's webVersionEnabled is true and its status is \"sent\" or \"archive\" (when adding this tag, also set webVersionEnabled: true), and always shows the latest version of the campaign (edits made after sending are visible to earlier recipients).\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"
          },
          "published": {
            "type": "boolean",
            "description": "When true, the form is reachable at the BlueFox-hosted URL bluefox.email/signup/{slug}. Requires a slug - either set here or already on the form."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the BlueFox-hosted signup page. Not generated automatically; rejected with a 400 if already taken by another form."
          },
          "pageHeadline": {
            "type": "string",
            "description": "Shown as the heading on the BlueFox-hosted signup page. Falls back to the project name if not set."
          },
          "pageDescription": {
            "type": "string",
            "description": "Shown under the headline on the BlueFox-hosted signup page."
          },
          "useDefaultTurnstile": {
            "type": "boolean",
            "description": "Defaults to true. When true, the BlueFox-hosted page (not embeds) shows and validates BlueFox's own Turnstile challenge, regardless of captchaType below - which still governs embeds, and governs the hosted page too when this is false."
          },
          "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."
              }
            }
          }
        }
      }
    }
  }
}