Public integration API

Galassify Broadcast 0.20.0rc1. Download OpenAPI JSON

Integrate a signup form

  1. Fetch GET /api/v1/public/organisations/{slug} and its subjects. Show the organisation's descriptions and opt-in setting.
  2. Default to all returned subjects. Omit subject_ids to select all current subjects; an empty array is allowed only when the organisation has none.
  3. POST JSON with email, optional names and choices to /api/v1/public/organisations/{slug}/subscriptions. Use credentials: "omit". No administrator cookie or API key.
  4. Show the generic 202 message exactly as returned. It confirms processing, not membership, activation or inbox delivery.
  5. Display 422 field errors, respect 429 Retry-After, explain disabled signup on 409 and allow retry on 503. Never infer whether an address already exists.

Your exact website origin must be configured in the organisation's allowlist. CORS has no wildcard or credentials. The central preferences request is same-origin; link visitors to the hosted preferences portal.

One association uses organisation SMTP; multiple associations use one neutral central email and one scoped link, including disabled associations. Missing transport gives the same public response, with no fallback. Only preferences mail bypasses disabled status. Confirmation and resubscription require explicit capability actions.

Operations

GET /assets/{storage_key} — Public Image

Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.

Scope: public/capability

Parameters

{
  "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.",
  "operationId": "public_image_assets__storage_key__get",
  "parameters": [
    {
      "in": "path",
      "name": "storage_key",
      "required": true,
      "schema": {
        "format": "uuid",
        "title": "Storage Key",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "image/*": {
          "schema": {
            "format": "binary",
            "type": "string"
          }
        }
      },
      "description": "Public image or unsubscribe confirmation."
    },
    "403": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Public Image",
  "tags": [
    "Assets"
  ],
  "x-required-role": "public/capability"
}
GET /api/v1/public/organisations/{slug} — Organisation

Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state.

Scope: public/capability

Parameters

{
  "description": "Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state.",
  "operationId": "organisation_api_v1_public_organisations__slug__get",
  "parameters": [
    {
      "in": "path",
      "name": "slug",
      "required": true,
      "schema": {
        "title": "Slug",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "properties": {
              "data": {
                "$ref": "#/components/schemas/ResultPublicOrganisation"
              }
            },
            "required": [
              "data"
            ],
            "type": "object"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Organisation",
  "tags": [
    "Signup"
  ],
  "x-required-role": "public/capability"
}
GET /api/v1/public/organisations/{slug}/subjects — Subjects

Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state.

Scope: public/capability

Parameters

{
  "description": "Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state.",
  "operationId": "subjects_api_v1_public_organisations__slug__subjects_get",
  "parameters": [
    {
      "in": "path",
      "name": "slug",
      "required": true,
      "schema": {
        "title": "Slug",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "properties": {
              "data": {
                "$ref": "#/components/schemas/ResultSubjects"
              }
            },
            "required": [
              "data"
            ],
            "type": "object"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Subjects",
  "tags": [
    "Signup"
  ],
  "x-required-role": "public/capability"
}
POST /api/v1/public/organisations/{slug}/subscriptions — Subscribe

Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state.

Scope: public/capability

Parameters

{
  "description": "Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state.",
  "operationId": "subscribe_api_v1_public_organisations__slug__subscriptions_post",
  "parameters": [
    {
      "in": "path",
      "name": "slug",
      "required": true,
      "schema": {
        "title": "Slug",
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "example": {
          "email": "reader@example.com",
          "first_name": "Sam"
        },
        "schema": {
          "$ref": "#/components/schemas/Subscription"
        }
      }
    },
    "required": true
  },
  "responses": {
    "202": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultGeneric"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Subscribe",
  "tags": [
    "Signup"
  ],
  "x-required-role": "public/capability"
}
POST /api/v1/public/organisations/{slug}/confirmation-requests — Replacement

Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state.

Scope: public/capability

Parameters

{
  "description": "Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state.",
  "operationId": "replacement_api_v1_public_organisations__slug__confirmation_requests_post",
  "parameters": [
    {
      "in": "path",
      "name": "slug",
      "required": true,
      "schema": {
        "title": "Slug",
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/EmailRequest"
        }
      }
    },
    "required": true
  },
  "responses": {
    "202": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultGeneric"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Replacement",
  "tags": [
    "Signup"
  ],
  "x-required-role": "public/capability"
}
POST /api/v1/public/confirmations — Confirm

Token in JSON for server clients, or exchanged broadcast_activation cookie. Browser requests require canonical Origin and broadcast_activation_csrf via X-CSRF-Token. GET links never activate. Disabled organisations cannot activate.

Scope: public/capability

Parameters

{
  "description": "Token in JSON for server clients, or exchanged broadcast_activation cookie. Browser requests require canonical Origin and broadcast_activation_csrf via X-CSRF-Token. GET links never activate. Disabled organisations cannot activate.",
  "operationId": "confirm_api_v1_public_confirmations_post",
  "parameters": [
    {
      "description": "Required with capability cookie or a browser request.",
      "in": "header",
      "name": "Origin",
      "required": false,
      "schema": {
        "type": "string"
      }
    },
    {
      "description": "Required for browser/cookie activation.",
      "in": "header",
      "name": "X-CSRF-Token",
      "required": false,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Confirmation"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "properties": {
              "data": {
                "$ref": "#/components/schemas/ResultActivation"
              }
            },
            "required": [
              "data"
            ],
            "type": "object"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Confirm",
  "tags": [
    "Signup"
  ],
  "x-required-role": "public/capability"
}
POST /api/v1/public/resubscriptions — Resubscribe

Token in JSON for server clients, or exchanged broadcast_activation cookie. Browser requests require canonical Origin and broadcast_activation_csrf via X-CSRF-Token. GET links never activate. Disabled organisations cannot activate.

Scope: public/capability

Parameters

{
  "description": "Token in JSON for server clients, or exchanged broadcast_activation cookie. Browser requests require canonical Origin and broadcast_activation_csrf via X-CSRF-Token. GET links never activate. Disabled organisations cannot activate.",
  "operationId": "resubscribe_api_v1_public_resubscriptions_post",
  "parameters": [
    {
      "description": "Required with capability cookie or a browser request.",
      "in": "header",
      "name": "Origin",
      "required": false,
      "schema": {
        "type": "string"
      }
    },
    {
      "description": "Required for browser/cookie activation.",
      "in": "header",
      "name": "X-CSRF-Token",
      "required": false,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Resubscription"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "properties": {
              "data": {
                "$ref": "#/components/schemas/ResultActivation"
              }
            },
            "required": [
              "data"
            ],
            "type": "object"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Resubscribe",
  "tags": [
    "Signup"
  ],
  "x-required-role": "public/capability"
}
POST /api/v1/public/preferences-requests — Request Link

Same generic 202 for zero/one/multiple associations, cooldown and missing/unhealthy SMTP. One organisation uses its sender; multiple use neutral central mail. Disabled associations remain eligible for preferences only. No source fallback.

Scope: public/capability

Parameters

{
  "description": "Same generic 202 for zero/one/multiple associations, cooldown and missing/unhealthy SMTP. One organisation uses its sender; multiple use neutral central mail. Disabled associations remain eligible for preferences only. No source fallback.",
  "operationId": "request_link_api_v1_public_preferences_requests_post",
  "parameters": [
    {
      "description": "Exact configured application origin; this endpoint is same-origin, not organisation CORS.",
      "in": "header",
      "name": "Origin",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "example": {
          "email": "reader@example.com"
        },
        "schema": {
          "$ref": "#/components/schemas/EmailRequest"
        }
      }
    },
    "required": true
  },
  "responses": {
    "202": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultGeneric"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Request Link",
  "tags": [
    "Preferences"
  ],
  "x-required-role": "public/capability"
}
GET /api/v1/public/preferences — Preferences

Only existing capability grants. Server clients may use X-Preferences-Token without Origin. Browser/cookie mutations require canonical Origin and scoped X-CSRF-Token; no admin session.

Scope: public/capability

{
  "description": "Only existing capability grants. Server clients may use X-Preferences-Token without Origin. Browser/cookie mutations require canonical Origin and scoped X-CSRF-Token; no admin session.",
  "operationId": "preferences_api_v1_public_preferences_get",
  "parameters": [],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "properties": {
              "data": {
                "$ref": "#/components/schemas/ResultPreferences"
              }
            },
            "required": [
              "data"
            ],
            "type": "object"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [
    {
      "PreferencesCapability": []
    },
    {
      "PreferencesCookie": []
    }
  ],
  "summary": "Preferences",
  "tags": [
    "Preferences"
  ],
  "x-required-role": "public/capability"
}
PATCH /api/v1/public/preferences/{org_id} — Update

Only existing capability grants. Server clients may use X-Preferences-Token without Origin. Browser/cookie mutations require canonical Origin and scoped X-CSRF-Token; no admin session.

Scope: public/capability

Parameters

{
  "description": "Only existing capability grants. Server clients may use X-Preferences-Token without Origin. Browser/cookie mutations require canonical Origin and scoped X-CSRF-Token; no admin session.",
  "operationId": "update_api_v1_public_preferences__org_id__patch",
  "parameters": [
    {
      "in": "path",
      "name": "org_id",
      "required": true,
      "schema": {
        "format": "uuid",
        "title": "Org Id",
        "type": "string"
      }
    },
    {
      "description": "Required for cookie/browser requests.",
      "in": "header",
      "name": "Origin",
      "required": false,
      "schema": {
        "type": "string"
      }
    },
    {
      "description": "Scoped CSRF from the hosted preferences page, required for cookie/browser requests.",
      "in": "header",
      "name": "X-CSRF-Token",
      "required": false,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Choices"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "properties": {
              "data": {
                "$ref": "#/components/schemas/ResultPreferenceChange"
              }
            },
            "required": [
              "data"
            ],
            "type": "object"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [
    {
      "PreferencesCapability": []
    },
    {
      "PreferencesCookie": []
    }
  ],
  "summary": "Update",
  "tags": [
    "Preferences"
  ],
  "x-required-role": "public/capability"
}
POST /api/v1/public/preferences/{org_id}/unsubscribe — Unsubscribe

Only existing capability grants. Server clients may use X-Preferences-Token without Origin. Browser/cookie mutations require canonical Origin and scoped X-CSRF-Token; no admin session.

Scope: public/capability

Parameters

{
  "description": "Only existing capability grants. Server clients may use X-Preferences-Token without Origin. Browser/cookie mutations require canonical Origin and scoped X-CSRF-Token; no admin session.",
  "operationId": "unsubscribe_api_v1_public_preferences__org_id__unsubscribe_post",
  "parameters": [
    {
      "in": "path",
      "name": "org_id",
      "required": true,
      "schema": {
        "format": "uuid",
        "title": "Org Id",
        "type": "string"
      }
    },
    {
      "description": "Required for cookie/browser requests.",
      "in": "header",
      "name": "Origin",
      "required": false,
      "schema": {
        "type": "string"
      }
    },
    {
      "description": "Scoped CSRF from the hosted preferences page, required for cookie/browser requests.",
      "in": "header",
      "name": "X-CSRF-Token",
      "required": false,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Withdrawal"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "properties": {
              "data": {
                "$ref": "#/components/schemas/ResultPreferenceChange"
              }
            },
            "required": [
              "data"
            ],
            "type": "object"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [
    {
      "PreferencesCapability": []
    },
    {
      "PreferencesCookie": []
    }
  ],
  "summary": "Unsubscribe",
  "tags": [
    "Preferences"
  ],
  "x-required-role": "public/capability"
}
GET /u/{raw} — Direct Page

Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.

Scope: public/capability

Parameters

{
  "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.",
  "operationId": "direct_page_u__raw__get",
  "parameters": [
    {
      "in": "path",
      "name": "raw",
      "required": true,
      "schema": {
        "title": "Raw",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Public image or unsubscribe confirmation."
    },
    "403": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Direct Page",
  "tags": [
    "Preferences"
  ],
  "x-required-role": "public/capability"
}
POST /u/{raw} — Direct Unsubscribe

Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.

Scope: public/capability

Parameters

{
  "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.",
  "operationId": "direct_unsubscribe_u__raw__post",
  "parameters": [
    {
      "in": "path",
      "name": "raw",
      "required": true,
      "schema": {
        "title": "Raw",
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/x-www-form-urlencoded": {
        "schema": {
          "properties": {
            "List-Unsubscribe": {
              "const": "One-Click"
            }
          },
          "required": [
            "List-Unsubscribe"
          ],
          "type": "object"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultUnsubscribe"
          }
        },
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Successful result. 202 means durable processing, not delivery."
    },
    "403": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Role, origin or CSRF denied."
    },
    "404": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Missing or inaccessible resource; tenant existence is not disclosed."
    },
    "409": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition."
    },
    "410": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Expired operation or invalid/expired capability."
    },
    "413": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request or upload exceeds its limit."
    },
    "415": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Unsupported content type."
    },
    "422": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Validation failed; unknown mutation fields are rejected."
    },
    "429": {
      "content": {
        "text/html": {
          "schema": {
            "type": "string"
          }
        }
      },
      "description": "Rate limited; obey Retry-After.",
      "headers": {
        "Retry-After": {
          "description": "Seconds until retry.",
          "schema": {
            "type": "integer"
          }
        }
      }
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultError"
          }
        }
      },
      "description": "Request could not be durably processed."
    }
  },
  "security": [],
  "summary": "Direct Unsubscribe",
  "tags": [
    "Preferences"
  ],
  "x-required-role": "public/capability"
}
GET /health/live — Live

Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.

Scope: public/capability

{
  "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.",
  "operationId": "live_health_live_get",
  "parameters": [],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultProbe"
          }
        }
      },
      "description": "Healthy probe."
    }
  },
  "security": [],
  "summary": "Live",
  "tags": [
    "Main"
  ],
  "x-required-role": "public/capability"
}
GET /health/ready — Readiness

Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.

Scope: public/capability

{
  "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.",
  "operationId": "readiness_health_ready_get",
  "parameters": [],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultProbe"
          }
        }
      },
      "description": "Healthy probe."
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultProbe"
          }
        }
      },
      "description": "Not ready or degraded."
    }
  },
  "security": [],
  "summary": "Readiness",
  "tags": [
    "Main"
  ],
  "x-required-role": "public/capability"
}
GET /health — Health

Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.

Scope: public/capability

{
  "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.",
  "operationId": "health_health_get",
  "parameters": [],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultProbe"
          }
        }
      },
      "description": "Healthy probe."
    },
    "503": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ResultProbe"
          }
        }
      },
      "description": "Not ready or degraded."
    }
  },
  "security": [],
  "summary": "Health",
  "tags": [
    "Main"
  ],
  "x-required-role": "public/capability"
}

Component schemas

Complete machine-readable contract
{
  "openapi": "3.1.0",
  "info": {
    "title": "Galassify Broadcast \u2014 Public integration",
    "description": "Actual implemented operations. Accepted public requests do not prove activation or inbox delivery. Public signup uses no admin cookie or API key. Capability endpoints have their own authority.",
    "version": "0.20.0rc1"
  },
  "paths": {
    "/assets/{storage_key}": {
      "get": {
        "summary": "Public Image",
        "operationId": "public_image_assets__storage_key__get",
        "parameters": [
          {
            "name": "storage_key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Storage Key"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Public image or unsubscribe confirmation.",
            "content": {
              "image/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Assets"
        ],
        "x-required-role": "public/capability",
        "security": [],
        "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow."
      }
    },
    "/api/v1/public/organisations/{slug}": {
      "get": {
        "summary": "Organisation",
        "operationId": "organisation_api_v1_public_organisations__slug__get",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Slug"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ResultPublicOrganisation"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Signup"
        ],
        "x-required-role": "public/capability",
        "security": [],
        "description": "Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state."
      }
    },
    "/api/v1/public/organisations/{slug}/subjects": {
      "get": {
        "summary": "Subjects",
        "operationId": "subjects_api_v1_public_organisations__slug__subjects_get",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Slug"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ResultSubjects"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Signup"
        ],
        "x-required-role": "public/capability",
        "security": [],
        "description": "Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state."
      }
    },
    "/api/v1/public/organisations/{slug}/subscriptions": {
      "post": {
        "summary": "Subscribe",
        "operationId": "subscribe_api_v1_public_organisations__slug__subscriptions_post",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Slug"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Subscription"
              },
              "example": {
                "email": "reader@example.com",
                "first_name": "Sam"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultGeneric"
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Signup"
        ],
        "x-required-role": "public/capability",
        "security": [],
        "description": "Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state."
      }
    },
    "/api/v1/public/organisations/{slug}/confirmation-requests": {
      "post": {
        "summary": "Replacement",
        "operationId": "replacement_api_v1_public_organisations__slug__confirmation_requests_post",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Slug"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultGeneric"
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Signup"
        ],
        "x-required-role": "public/capability",
        "security": [],
        "description": "Exact configured organisation CORS origins only; credentials omitted. Omitted subject_ids selects all; explicit [] is rejected when subjects exist. Generic success depends only on public opt-in mode, not address state."
      }
    },
    "/api/v1/public/confirmations": {
      "post": {
        "summary": "Confirm",
        "operationId": "confirm_api_v1_public_confirmations_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Confirmation"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ResultActivation"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Signup"
        ],
        "x-required-role": "public/capability",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required with capability cookie or a browser request."
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required for browser/cookie activation."
          }
        ],
        "security": [],
        "description": "Token in JSON for server clients, or exchanged broadcast_activation cookie. Browser requests require canonical Origin and broadcast_activation_csrf via X-CSRF-Token. GET links never activate. Disabled organisations cannot activate."
      }
    },
    "/api/v1/public/resubscriptions": {
      "post": {
        "summary": "Resubscribe",
        "operationId": "resubscribe_api_v1_public_resubscriptions_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Resubscription"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ResultActivation"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Signup"
        ],
        "x-required-role": "public/capability",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required with capability cookie or a browser request."
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required for browser/cookie activation."
          }
        ],
        "security": [],
        "description": "Token in JSON for server clients, or exchanged broadcast_activation cookie. Browser requests require canonical Origin and broadcast_activation_csrf via X-CSRF-Token. GET links never activate. Disabled organisations cannot activate."
      }
    },
    "/api/v1/public/preferences-requests": {
      "post": {
        "summary": "Request Link",
        "operationId": "request_link_api_v1_public_preferences_requests_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailRequest"
              },
              "example": {
                "email": "reader@example.com"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultGeneric"
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Preferences"
        ],
        "x-required-role": "public/capability",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Exact configured application origin; this endpoint is same-origin, not organisation CORS."
          }
        ],
        "security": [],
        "description": "Same generic 202 for zero/one/multiple associations, cooldown and missing/unhealthy SMTP. One organisation uses its sender; multiple use neutral central mail. Disabled associations remain eligible for preferences only. No source fallback."
      }
    },
    "/api/v1/public/preferences": {
      "get": {
        "summary": "Preferences",
        "operationId": "preferences_api_v1_public_preferences_get",
        "responses": {
          "200": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ResultPreferences"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Preferences"
        ],
        "x-required-role": "public/capability",
        "parameters": [],
        "security": [
          {
            "PreferencesCapability": []
          },
          {
            "PreferencesCookie": []
          }
        ],
        "description": "Only existing capability grants. Server clients may use X-Preferences-Token without Origin. Browser/cookie mutations require canonical Origin and scoped X-CSRF-Token; no admin session."
      }
    },
    "/api/v1/public/preferences/{org_id}": {
      "patch": {
        "summary": "Update",
        "operationId": "update_api_v1_public_preferences__org_id__patch",
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Org Id"
            }
          },
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required for cookie/browser requests."
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scoped CSRF from the hosted preferences page, required for cookie/browser requests."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Choices"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ResultPreferenceChange"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Preferences"
        ],
        "x-required-role": "public/capability",
        "security": [
          {
            "PreferencesCapability": []
          },
          {
            "PreferencesCookie": []
          }
        ],
        "description": "Only existing capability grants. Server clients may use X-Preferences-Token without Origin. Browser/cookie mutations require canonical Origin and scoped X-CSRF-Token; no admin session."
      }
    },
    "/api/v1/public/preferences/{org_id}/unsubscribe": {
      "post": {
        "summary": "Unsubscribe",
        "operationId": "unsubscribe_api_v1_public_preferences__org_id__unsubscribe_post",
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Org Id"
            }
          },
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required for cookie/browser requests."
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scoped CSRF from the hosted preferences page, required for cookie/browser requests."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Withdrawal"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ResultPreferenceChange"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Preferences"
        ],
        "x-required-role": "public/capability",
        "security": [
          {
            "PreferencesCapability": []
          },
          {
            "PreferencesCookie": []
          }
        ],
        "description": "Only existing capability grants. Server clients may use X-Preferences-Token without Origin. Browser/cookie mutations require canonical Origin and scoped X-CSRF-Token; no admin session."
      }
    },
    "/u/{raw}": {
      "get": {
        "summary": "Direct Page",
        "operationId": "direct_page_u__raw__get",
        "parameters": [
          {
            "name": "raw",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Raw"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Public image or unsubscribe confirmation.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Preferences"
        ],
        "x-required-role": "public/capability",
        "security": [],
        "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow."
      },
      "post": {
        "summary": "Direct Unsubscribe",
        "operationId": "direct_unsubscribe_u__raw__post",
        "parameters": [
          {
            "name": "raw",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Raw"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful result. 202 means durable processing, not delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultUnsubscribe"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "description": "Role, origin or CSRF denied.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Missing or inaccessible resource; tenant existence is not disclosed.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "409": {
            "description": "Conflict, stale revision/confirmation, disabled organisation or invalid transition.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "410": {
            "description": "Expired operation or invalid/expired capability.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "413": {
            "description": "Request or upload exceeds its limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed; unknown mutation fields are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; obey Retry-After.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Request could not be durably processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultError"
                }
              }
            }
          }
        },
        "tags": [
          "Preferences"
        ],
        "x-required-role": "public/capability",
        "security": [],
        "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow.",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "List-Unsubscribe": {
                    "const": "One-Click"
                  }
                },
                "required": [
                  "List-Unsubscribe"
                ]
              }
            }
          }
        }
      }
    },
    "/health/live": {
      "get": {
        "summary": "Live",
        "operationId": "live_health_live_get",
        "responses": {
          "200": {
            "description": "Healthy probe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultProbe"
                }
              }
            }
          }
        },
        "tags": [
          "Main"
        ],
        "x-required-role": "public/capability",
        "parameters": [],
        "security": [],
        "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow."
      }
    },
    "/health/ready": {
      "get": {
        "summary": "Readiness",
        "operationId": "readiness_health_ready_get",
        "responses": {
          "200": {
            "description": "Healthy probe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultProbe"
                }
              }
            }
          },
          "503": {
            "description": "Not ready or degraded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultProbe"
                }
              }
            }
          }
        },
        "tags": [
          "Main"
        ],
        "x-required-role": "public/capability",
        "parameters": [],
        "security": [],
        "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow."
      }
    },
    "/health": {
      "get": {
        "summary": "Health",
        "operationId": "health_health_get",
        "responses": {
          "200": {
            "description": "Healthy probe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultProbe"
                }
              }
            }
          },
          "503": {
            "description": "Not ready or degraded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultProbe"
                }
              }
            }
          }
        },
        "tags": [
          "Main"
        ],
        "x-required-role": "public/capability",
        "parameters": [],
        "security": [],
        "description": "Uses the shared domain service and current authorization checks. See the integration/operator walkthrough for the surrounding workflow."
      }
    }
  },
  "components": {
    "schemas": {
      "Choices": {
        "properties": {
          "subject_ids": {
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "type": "array",
            "maxItems": 1000,
            "title": "Subject Ids"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "subject_ids"
        ],
        "title": "Choices"
      },
      "Confirmation": {
        "properties": {
          "token": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 43,
                "minLength": 43
              },
              {
                "type": "null"
              }
            ],
            "title": "Token"
          },
          "subject_ids": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "format": "uuid"
                },
                "type": "array",
                "maxItems": 1000
              },
              {
                "type": "null"
              }
            ],
            "title": "Subject Ids"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "Confirmation"
      },
      "EmailRequest": {
        "properties": {
          "email": {
            "type": "string",
            "maxLength": 254,
            "title": "Email"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "email"
        ],
        "title": "EmailRequest"
      },
      "Resubscription": {
        "properties": {
          "token": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 43,
                "minLength": 43
              },
              {
                "type": "null"
              }
            ],
            "title": "Token"
          },
          "subject_ids": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "format": "uuid"
                },
                "type": "array",
                "maxItems": 1000
              },
              {
                "type": "null"
              }
            ],
            "title": "Subject Ids"
          },
          "confirmed": {
            "type": "boolean",
            "title": "Confirmed"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "confirmed"
        ],
        "title": "Resubscription"
      },
      "Subscription": {
        "properties": {
          "email": {
            "type": "string",
            "maxLength": 254,
            "title": "Email"
          },
          "first_name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ],
            "title": "First Name"
          },
          "last_name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Name"
          },
          "subject_ids": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "format": "uuid"
                },
                "type": "array",
                "maxItems": 1000
              },
              {
                "type": "null"
              }
            ],
            "title": "Subject Ids"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "email"
        ],
        "title": "Subscription"
      },
      "Withdrawal": {
        "properties": {},
        "additionalProperties": false,
        "type": "object",
        "title": "Withdrawal"
      },
      "ResultError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "fields": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "request_id": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message",
              "fields",
              "request_id"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "ResultGeneric": {
        "type": "object",
        "properties": {
          "success": {
            "const": true
          },
          "status": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "success",
          "status",
          "message"
        ]
      },
      "ResultUnsubscribe": {
        "type": "object",
        "properties": {
          "success": {
            "const": true
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "success",
          "message"
        ]
      },
      "ResultPublicOrganisation": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "brand_colour": {
            "type": "string"
          },
          "background_mode": {
            "type": "string"
          },
          "signup_intro": {
            "type": "string"
          },
          "confirmation_intro": {
            "type": "string"
          },
          "double_opt_in": {
            "type": "boolean"
          },
          "signup_available": {
            "type": "boolean"
          },
          "logo_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "subjects": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "id": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "required": [
                "id",
                "name",
                "description"
              ]
            }
          }
        },
        "required": [
          "name",
          "slug",
          "subjects",
          "double_opt_in",
          "signup_available"
        ]
      },
      "ResultSubjects": {
        "type": "object",
        "properties": {
          "subjects": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "id": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "required": [
                "id",
                "name",
                "description"
              ]
            }
          }
        },
        "required": [
          "subjects"
        ]
      },
      "ResultActivation": {
        "type": "object",
        "properties": {
          "confirmed": {
            "const": true
          }
        },
        "required": [
          "confirmed"
        ]
      },
      "ResultPreferences": {
        "type": "object",
        "properties": {
          "central": {
            "type": "boolean"
          },
          "organisations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "slug": {
                  "type": "string"
                },
                "brand_colour": {
                  "type": "string"
                },
                "background_mode": {
                  "type": "string"
                },
                "signup_intro": {
                  "type": "string"
                },
                "confirmation_intro": {
                  "type": "string"
                },
                "double_opt_in": {
                  "type": "boolean"
                },
                "signup_available": {
                  "type": "boolean"
                },
                "logo_url": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "subjects": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "id": {
                        "type": "string",
                        "format": "uuid"
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "description"
                    ]
                  }
                },
                "preferences_intro": {
                  "type": "string"
                },
                "state": {
                  "type": "string"
                },
                "first_name": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "last_name": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "org_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "subject_ids": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              },
              "required": []
            }
          }
        },
        "required": [
          "central",
          "organisations"
        ]
      },
      "ResultPreferenceChange": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "brand_colour": {
            "type": "string"
          },
          "background_mode": {
            "type": "string"
          },
          "signup_intro": {
            "type": "string"
          },
          "confirmation_intro": {
            "type": "string"
          },
          "double_opt_in": {
            "type": "boolean"
          },
          "signup_available": {
            "type": "boolean"
          },
          "logo_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "subjects": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "id": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "required": [
                "id",
                "name",
                "description"
              ]
            }
          },
          "preferences_intro": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "first_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "subject_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          }
        },
        "required": []
      },
      "ResultProbe": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string"
          },
          "version": {
            "type": "string"
          }
        },
        "required": [
          "status",
          "version"
        ]
      }
    },
    "securitySchemes": {
      "PreferencesCapability": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Preferences-Token"
      },
      "PreferencesCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "broadcast_preferences"
      }
    }
  }
}