{
  "openapi": "3.1.0",
  "info": {
    "title": "Hail",
    "description": "Give your AI agent a voice, a real phone number, and an inbox.\n\nThis file is the source of truth for the Go CLI. Regenerate it after\nchanging API routes — see docs/public/contributing.md.\n",
    "version": "0.1.0"
  },
  "servers": [
    {
      "url": "https://api.hail.so",
      "description": "Hail Cloud"
    }
  ],
  "paths": {
    "/v1/calls": {
      "post": {
        "tags": [
          "calls"
        ],
        "summary": "Create Call",
        "description": "Place an outbound AI voice call.\n\nThe call is placed asynchronously — this returns as soon as the call is\nqueued, not when it completes. Poll GET /v1/calls/{call_id} or configure a\nwebhook to get the final status and transcript. Requires\nrecipient_consent=true on the request body; Hail does not verify lawful\nbasis to contact the recipient, the caller warrants it.",
        "operationId": "create_call_v1_calls_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Idempotency-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. The agent-origin workspace exceeded a per-channel velocity cap, or the platform kill switch is on. Retry after the Retry-After header (seconds). Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "calls"
        ],
        "summary": "List Calls",
        "description": "List calls for the caller's organization, newest first.\n\nCursor-paginated: pass the returned next_cursor to fetch the next page;\na null next_cursor means there are no more results. Filter by status or\ndestination number (to) to narrow the list.",
        "operationId": "list_calls_v1_calls_get",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "queued",
                    "dialing",
                    "ringing",
                    "in_progress",
                    "completed",
                    "failed",
                    "busy",
                    "no_answer",
                    "canceled"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Status"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "To"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/calls/{call_id}": {
      "get": {
        "tags": [
          "calls"
        ],
        "summary": "Get Call",
        "description": "Fetch one call by id, including its current status and end reason.\n\nOrg-scoped: returns 404 for a call belonging to a different organization\n(not 403, to avoid confirming the id exists). Use this to poll for the\nfinal outcome of a call placed with POST /v1/calls.",
        "operationId": "get_call_v1_calls__call_id__get",
        "parameters": [
          {
            "name": "call_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Call Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/email-attachments": {
      "post": {
        "tags": [
          "email-attachments"
        ],
        "summary": "Create Email Attachment",
        "description": "Upload a file and get back a reusable attachment id.\n\nThe returned id can be referenced from attachment_ids on many later\nPOST /v1/emails calls until it is garbage-collected for being unused; it is\nnot deleted immediately after first use. Uploads are size-limited and\nscoped to the caller's organization.",
        "operationId": "upload_email_attachment",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/Body_upload_email_attachment"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailAttachmentUploadResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails": {
      "post": {
        "tags": [
          "emails"
        ],
        "summary": "Create Email",
        "description": "Send an outbound email through SES.\n\nSends synchronously — the response reports the final status (sent or\nfailed), not a queued placeholder; no separate poll is needed for the\nhappy path, though a bounce or complaint can still arrive later as a\nwebhook or GET /v1/emails/{email_id}/events entry. Requires\nrecipient_consent=true on the request body; Hail does not verify lawful\nbasis to contact the recipient, the caller warrants it.",
        "operationId": "create_email_v1_emails_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Idempotency-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. The agent-origin workspace exceeded a per-channel velocity cap, or the platform kill switch is on. Retry after the Retry-After header (seconds). Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "emails"
        ],
        "summary": "List Emails",
        "description": "List emails for the caller's organization, newest first.\n\nCursor-paginated: pass the returned next_cursor to fetch the next page;\na null next_cursor means there are no more results. Filter by status or\ndirection (outbound/inbound). List entries omit body_text/body_html —\nfetch GET /v1/emails/{email_id} for the full body.",
        "operationId": "list_emails_v1_emails_get",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "queued",
                    "sent",
                    "delivered",
                    "failed",
                    "bounced",
                    "complained",
                    "received"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Status"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "outbound",
                    "inbound"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Direction"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails/{email_id}/events": {
      "get": {
        "tags": [
          "emails"
        ],
        "summary": "List Email Events",
        "description": "Chronological lifecycle events for one email (org-scoped).\n\nCursor-paginated with the same forward-walk shape as ``GET /events``:\nstrictly-greater on ``(occurred_at, id)``, ascending.",
        "operationId": "list_email_events_v1_emails__email_id__events_get",
        "parameters": [
          {
            "name": "email_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Email Id"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 1000,
              "minimum": 1,
              "default": 100,
              "title": "Limit"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailEventListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails/stats": {
      "get": {
        "tags": [
          "emails"
        ],
        "summary": "Get Email Stats",
        "description": "Aggregate send/delivery/open/click/bounce counts and rates over a range.\n\nDefaults to the last 7 days, bucketed by day. bucket=hour is limited to\nan 8-day range; any bucket size is limited to a 92-day range. Registered\nabove GET /v1/emails/{email_id} so \"stats\" is not swallowed by the id path param.",
        "operationId": "get_email_stats_v1_emails_stats_get",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "title": "From"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "title": "To"
            }
          },
          {
            "name": "bucket",
            "in": "query",
            "required": false,
            "schema": {
              "enum": [
                "hour",
                "day"
              ],
              "type": "string",
              "default": "day",
              "title": "Bucket"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailStatsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails/{email_id}": {
      "get": {
        "tags": [
          "emails"
        ],
        "summary": "Get Email",
        "description": "Fetch one email by id, including attachments and last event time.\n\nOrg-scoped: returns 404 for an email belonging to a different\norganization. For an inbound email with a stored raw MIME, raw_url\npoints at GET /v1/emails/{email_id}/raw.",
        "operationId": "get_email_v1_emails__email_id__get",
        "parameters": [
          {
            "name": "email_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Email Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails/{email_id}/raw": {
      "get": {
        "tags": [
          "emails"
        ],
        "summary": "Get Email Raw",
        "description": "302 → presigned S3 URL for the raw inbound MIME (404 for outbound).",
        "operationId": "get_email_raw_v1_emails__email_id__raw_get",
        "parameters": [
          {
            "name": "email_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Email Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails/{email_id}/attachments/{attachment_id}": {
      "get": {
        "tags": [
          "emails"
        ],
        "summary": "Get Email Attachment",
        "description": "302 → presigned S3 URL for one attachment.",
        "operationId": "get_email_attachment_v1_emails__email_id__attachments__attachment_id__get",
        "parameters": [
          {
            "name": "email_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Email Id"
            }
          },
          {
            "name": "attachment_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Attachment Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/events": {
      "get": {
        "tags": [
          "events"
        ],
        "summary": "List Events",
        "description": "Cursor-paginated forward stream of call, email, and SMS events.\n\nScoped to the caller's organization. Pass id (typed \"<type>:<uuid>\",\ne.g. \"call:<uuid>\") to narrow to one resource's events, or kind to\nnarrow to one event kind. Walks forward in time — pass the returned\nnext_cursor to continue tailing where you left off.",
        "operationId": "list_events_v1_events_get",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 1000,
              "minimum": 1,
              "default": 100,
              "title": "Limit"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Id"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Kind"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventStreamResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/email-domains": {
      "post": {
        "tags": [
          "email-domains"
        ],
        "summary": "Create Email Domain",
        "description": "Register a sender identity to send outbound email through.\n\nkind=\"hail_mail\" mints an address on the shared hail-mail domain and is\nimmediately verified — no DNS work needed. kind=\"custom\" registers your\nown domain with SES and returns DKIM records; the domain stays\nunverified (POST /v1/email-domains/{domain_id}/verify) until you publish\nthose DNS records and Hail confirms them.",
        "operationId": "create_email_domain_v1_email_domains_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailDomainCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailDomainResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "email-domains"
        ],
        "summary": "List Email Domains",
        "description": "List sender domains/identities for the caller's organization.\n\nCursor-paginated, newest first. The response also includes\ndefault_from — the address a from-less POST /v1/emails would use right\nnow given the org's current verified senders.",
        "operationId": "list_email_domains_v1_email_domains_get",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailDomainListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/email-domains/check-domain": {
      "get": {
        "tags": [
          "email-domains"
        ],
        "summary": "Check Domain",
        "description": "Does this domain already receive mail? Drives apex-vs-prefix onboarding.",
        "operationId": "check_domain_v1_email_domains_check_domain_get",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Domain"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DomainCheckResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/email-domains/{domain_id}": {
      "get": {
        "tags": [
          "email-domains"
        ],
        "summary": "Get Email Domain",
        "description": "Fetch one sender domain/identity by id, including its DNS records.\n\nOrg-scoped: returns 404 for a domain belonging to a different\norganization. For a pending custom domain, dns_records lists the DKIM\nrecords still to publish.",
        "operationId": "get_email_domain_v1_email_domains__domain_id__get",
        "parameters": [
          {
            "name": "domain_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Domain Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailDomainResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "email-domains"
        ],
        "summary": "Patch Email Domain",
        "description": "Edit hail-mail prefixes and/or inbound action settings.\n\nTwo modes, mutually compatible:\n\n* **Prefix edit** (``local_prefix_user`` / ``local_prefix_org``):\n  hail_mail rows only. The managed-cloud console writes here when\n  an org admin changes the visible hail-mail address.\n* **Inbound action edit** (``inbound_enabled`` / ``forward_to`` /\n  ``forward_rate_per_hour``): any row kind.",
        "operationId": "patch_email_domain_v1_email_domains__domain_id__patch",
        "parameters": [
          {
            "name": "domain_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Domain Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailDomainPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailDomainResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "email-domains"
        ],
        "summary": "Delete Email Domain",
        "description": "Permanently remove a sender domain/identity.\n\nIrreversible — for a custom domain, also deletes the SES identity, so\nthe domain can no longer send until re-registered and re-verified.\nFails with 409 if any Email rows still reference this domain; delete\nor wait for those to age out first.",
        "operationId": "delete_email_domain_v1_email_domains__domain_id__delete",
        "parameters": [
          {
            "name": "domain_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Domain Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/email-domains/{domain_id}/verify": {
      "post": {
        "tags": [
          "email-domains"
        ],
        "summary": "Verify Email Domain",
        "description": "Re-poll the email provider for the current verification status.\n\nOn-demand only — there is no background poller in v1. Operators /\ntenants hit this after publishing DNS to flip the row to ``verified``.\nHail-mail rows are no-ops (they're already verified by construction).",
        "operationId": "verify_email_domain_v1_email_domains__domain_id__verify_post",
        "parameters": [
          {
            "name": "domain_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Domain Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailDomainResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/numbers": {
      "post": {
        "tags": [
          "numbers"
        ],
        "summary": "Acquire Number",
        "description": "Buy a dedicated phone number for the caller's organization.\n\nThis purchases a real number at the carrier and starts a recurring\nmonthly fee immediately — it is not a reservation. The number is usable\nfor voice, SMS, or both depending on the requested capabilities and\nwhat the carrier offers for the given country_code/number_type.",
        "operationId": "acquire_number_v1_numbers_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Idempotency-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NumberAcquireRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumberResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "numbers"
        ],
        "summary": "List Numbers",
        "description": "List dedicated numbers owned by the caller's organization.\n\nCursor-paginated, newest first. Only org-owned numbers are listed —\nshared pool numbers used for outbound calls never appear here.",
        "operationId": "list_numbers_v1_numbers_get",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumberListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/numbers/{number_id}": {
      "delete": {
        "tags": [
          "numbers"
        ],
        "summary": "Release Number",
        "description": "Release a dedicated number. The monthly fee stops accruing after the\nrelease month; months already accrued stay owed (the rater bills late,\nnever forgives).",
        "operationId": "release_number_v1_numbers__number_id__delete",
        "parameters": [
          {
            "name": "number_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Number Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "numbers"
        ],
        "summary": "Get Number",
        "description": "Fetch one dedicated number by id, including its capabilities and state.\n\nOrg-scoped: returns 404 for a number belonging to a different\norganization.",
        "operationId": "get_number_v1_numbers__number_id__get",
        "parameters": [
          {
            "name": "number_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Number Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumberResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/numbers/{number_id}/enable-sms": {
      "post": {
        "tags": [
          "numbers"
        ],
        "summary": "Enable Sms",
        "description": "Attach a dedicated number to the org's shared SMS Messaging Service.\n\nRequired once per number before it can send/receive SMS; the number\nmust already have been acquired with sms capability. Idempotent —\ncalling this again on an already-enabled number just returns its\ncurrent state. Fails with 422 for a released number or one that lacks\nsms capability.",
        "operationId": "enable_sms_v1_numbers__number_id__enable_sms_post",
        "parameters": [
          {
            "name": "number_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Number Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumberResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "Create Subscription",
        "description": "Create a webhook subscription for one or more event types.\n\nThe response includes the plaintext signing secret — this is the only\ntime it is ever returned; store it now. Every later GET omits it. Use\nPOST /v1/webhooks/{sub_id}/rotate-secret to get a new plaintext secret if\nit is lost or compromised.",
        "operationId": "create_subscription_v1_webhooks_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookSubscriptionCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSubscriptionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "webhooks"
        ],
        "summary": "List Subscriptions",
        "description": "List webhook subscriptions for the caller's organization.\n\nCursor-paginated, newest first. The signing secret is never included —\nonly POST /v1/webhooks and POST /v1/webhooks/{sub_id}/rotate-secret return it.",
        "operationId": "list_subscriptions_v1_webhooks_get",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSubscriptionListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{sub_id}": {
      "get": {
        "tags": [
          "webhooks"
        ],
        "summary": "Get Subscription",
        "description": "Fetch one webhook subscription by id. The signing secret is omitted.",
        "operationId": "get_subscription_v1_webhooks__sub_id__get",
        "parameters": [
          {
            "name": "sub_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Sub Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSubscriptionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "webhooks"
        ],
        "summary": "Patch Subscription",
        "description": "Update a webhook subscription's target_url, event_types, and/or status.\n\nOnly fields present in the request body are changed. Setting\nstatus=\"active\" resets the consecutive-failure counter, so a\nsubscription that was auto-disabled after 50 straight delivery\nfailures does not immediately re-disable itself.",
        "operationId": "patch_subscription_v1_webhooks__sub_id__patch",
        "parameters": [
          {
            "name": "sub_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Sub Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookSubscriptionPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSubscriptionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "webhooks"
        ],
        "summary": "Delete Subscription",
        "description": "Permanently remove a webhook subscription.\n\nIrreversible — no further events are delivered to it, and its\ndelivery history is deleted with it.",
        "operationId": "delete_subscription_v1_webhooks__sub_id__delete",
        "parameters": [
          {
            "name": "sub_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Sub Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{sub_id}/rotate-secret": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "Rotate Secret",
        "description": "Generate a new signing secret and immediately invalidate the old one.\n\nThe response includes the new plaintext secret — this is the only\ntime it is returned; update your verification code with it right away,\nsince the old secret stops validating new deliveries immediately.",
        "operationId": "rotate_secret_v1_webhooks__sub_id__rotate_secret_post",
        "parameters": [
          {
            "name": "sub_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Sub Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSubscriptionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{sub_id}/deliveries": {
      "get": {
        "tags": [
          "webhooks"
        ],
        "summary": "List Deliveries",
        "description": "List delivery attempts for one webhook subscription, newest first.\n\nCursor-paginated. Each entry shows the attempt count, response status,\nand response body Hail recorded — use POST /v1/webhooks/{sub_id}/\ndeliveries/{delivery_id}/redeliver to retry a failed one.",
        "operationId": "list_deliveries_v1_webhooks__sub_id__deliveries_get",
        "parameters": [
          {
            "name": "sub_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Sub Id"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{sub_id}/deliveries/{delivery_id}/redeliver": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "Redeliver",
        "description": "Retry one webhook delivery attempt.\n\nResets it to pending with a fresh attempt counter — the delivery\nworker picks it up and re-sends the same event payload to target_url\nshortly after. Useful after fixing an endpoint that was returning\nerrors.",
        "operationId": "redeliver_v1_webhooks__sub_id__deliveries__delivery_id__redeliver_post",
        "parameters": [
          {
            "name": "sub_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Sub Id"
            }
          },
          {
            "name": "delivery_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Delivery Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/unsubscribe": {
      "get": {
        "tags": [
          "unsubscribe"
        ],
        "summary": "Unsubscribe",
        "description": "One-click email opt-out (RFC 8058), reached by clicking a link in a sent email.\n\nPublic and unauthenticated — the signed token query param is the sole\ncredential, proving the caller holds a link Hail sent to that address.\nOn success, the address is added to the org's suppression list and all\nfuture outbound email to it is blocked. Returns an HTML page, not JSON.",
        "operationId": "unsubscribe_v1_unsubscribe_get",
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Token"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sms": {
      "post": {
        "tags": [
          "sms"
        ],
        "summary": "Create Sms",
        "description": "Send an outbound SMS.\n\nSends synchronously — the response reports the final status (sent or\nfailed), not a queued placeholder, though delivery confirmation from\nthe carrier can still arrive later as a webhook or GET /v1/sms/{sms_id}\nupdate. An explicit from resolves a dedicated number; otherwise Hail\npicks an alphanumeric sender ID where the destination corridor allows\nit, or requires a dedicated SMS-capable number otherwise. Requires\nrecipient_consent=true on the request body; Hail does not verify\nlawful basis to contact the recipient, the caller warrants it.",
        "operationId": "create_sms_v1_sms_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Idempotency-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SmsCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. The agent-origin workspace exceeded a per-channel velocity cap, or the platform kill switch is on. Retry after the Retry-After header (seconds). Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "sms"
        ],
        "summary": "List Sms",
        "description": "List SMS messages for the caller's organization, newest first.\n\nCursor-paginated: pass the returned next_cursor to fetch the next page;\na null next_cursor means there are no more results. Filter by status or\ndestination number (to) to narrow the list.",
        "operationId": "list_sms_v1_sms_get",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "queued",
                    "sent",
                    "delivered",
                    "failed",
                    "undelivered",
                    "received"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Status"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "To"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sms/suppressions": {
      "get": {
        "tags": [
          "sms"
        ],
        "summary": "List Sms Suppressions",
        "description": "List SMS numbers suppressed from receiving messages, newest first.\n\nCursor-paginated. A suppressed number blocks POST /v1/sms sends to it\nwith a 403 until removed via DELETE /v1/sms/suppressions/{number}.",
        "operationId": "list_sms_suppressions_v1_sms_suppressions_get",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuppressionListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sms/suppressions/{number}": {
      "delete": {
        "tags": [
          "sms"
        ],
        "summary": "Delete Sms Suppression",
        "description": "Remove one number from the SMS suppression list, re-allowing sends to it.\n\nDoes not itself constitute renewed consent — the caller is responsible\nfor having a lawful basis (e.g. a fresh opt-in) before sending again.\nReturns 404 if the number was not suppressed.",
        "operationId": "delete_sms_suppression_v1_sms_suppressions__number__delete",
        "parameters": [
          {
            "name": "number",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Number"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sms/sender-id": {
      "get": {
        "tags": [
          "sms"
        ],
        "summary": "Get Sender Id",
        "description": "Get the org's custom alphanumeric SMS sender ID, if any is set.\n\neffective_default is the platform sender id used for\nalphanumeric-eligible corridors when custom_sender_id is null.",
        "operationId": "get_sender_id_v1_sms_sender_id_get",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SenderIdResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "sms"
        ],
        "summary": "Patch Sender Id",
        "description": "Set or clear the org's custom alphanumeric SMS sender ID.\n\nPass custom_sender_id=null to clear it and fall back to the platform\ndefault sender id. Only affects alphanumeric-eligible corridors — a\ncorridor requiring a dedicated number is unaffected.",
        "operationId": "patch_sender_id_v1_sms_sender_id_patch",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SenderIdPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SenderIdResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sms/{sms_id}": {
      "get": {
        "tags": [
          "sms"
        ],
        "summary": "Get Sms",
        "description": "Fetch one SMS by id, including its current status.\n\nOrg-scoped: returns 404 for an SMS belonging to a different\norganization.",
        "operationId": "get_sms_v1_sms__sms_id__get",
        "parameters": [
          {
            "name": "sms_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Sms Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/contacts": {
      "get": {
        "tags": [
          "contacts"
        ],
        "summary": "List Contacts",
        "description": "List contacts for the caller's organization, newest first.\n\nMerges two sources into one list: org members (kind=\"member\", ids\nprefixed \"member:\", managed via membership — not editable here) and\nmanually-created contacts (kind=\"manual\", editable via PATCH/DELETE\n/contacts/{contact_id}). Cursor-paginated; q does a substring search\nover name/phone/email.",
        "operationId": "list_contacts_v1_contacts_get",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Q"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 500,
              "minimum": 1,
              "default": 100,
              "title": "Limit"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "contacts"
        ],
        "summary": "Create Contact",
        "description": "Create a manual contact with a phone and/or an email.\n\nRequires at least one of phone_e164 or email. Fails with 409 if a\ncontact with the same phone or email already exists in this\norganization.",
        "operationId": "create_contact_v1_contacts_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactEntry"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/contacts/{contact_id}": {
      "patch": {
        "tags": [
          "contacts"
        ],
        "summary": "Patch Contact",
        "description": "Update a manual contact's fields. Only fields present in the body change.\n\nManual contacts only — a member: id (org members synced from\nmembership) returns 422; edit those via the membership APIs instead.\nThe contact must still have at least one of phone_e164 or email after\nthe update. Fails with 409 on a duplicate phone/email.",
        "operationId": "patch_contact_v1_contacts__contact_id__patch",
        "parameters": [
          {
            "name": "contact_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Contact Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactEntry"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "contacts"
        ],
        "summary": "Delete Contact",
        "description": "Permanently remove a manual contact.\n\nManual contacts only — a member: id returns 422; org members are\nremoved via the membership APIs, not this route. Irreversible.",
        "operationId": "delete_contact_v1_contacts__contact_id__delete",
        "parameters": [
          {
            "name": "contact_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Contact Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/members/{user_id}/phone": {
      "put": {
        "tags": [
          "contacts"
        ],
        "summary": "Put Member Phone",
        "description": "Set an org member's phone number.\n\nPass user_id=\"me\" to set your own, or a member's user id — setting\nanother member's phone requires the caller to be an org owner or\nadmin. Returns 404 if the target is not a member of this organization.",
        "operationId": "put_member_phone_v1_members__user_id__phone_put",
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "User Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MemberPhonePut"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "string"
                  },
                  "title": "Response Put Member Phone V1 Members  User Id  Phone Put"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "contacts"
        ],
        "summary": "Delete Member Phone",
        "description": "Clear an org member's phone number.\n\nPass user_id=\"me\" to clear your own, or a member's user id — clearing\nanother member's phone requires the caller to be an org owner or\nadmin. Returns 404 if the target is not a member of this organization.",
        "operationId": "delete_member_phone_v1_members__user_id__phone_delete",
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "User Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/whoami": {
      "get": {
        "tags": [
          "whoami"
        ],
        "summary": "Get Whoami",
        "description": "Identify the caller: auth kind, organization, and (if resolvable) user.\n\nUseful for an agent that needs the human's address to put in\nReply-To, since the bearer token itself only carries an organization.\nuser_id/email/name come back null for a shared-key\n(HAIL_API_KEY) call, which has no individual user behind it.",
        "operationId": "get_whoami_v1_whoami_get",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhoamiResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/providers": {
      "get": {
        "tags": [
          "providers"
        ],
        "summary": "List Providers",
        "description": "Every saved provider row for the caller's organization, all layers.",
        "operationId": "list_providers",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderConfigListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/providers/{layer}": {
      "put": {
        "tags": [
          "providers"
        ],
        "summary": "Upsert Provider",
        "description": "Save a provider for ``layer`` and make it the active one.\n\nA partial write: anything you omit keeps its saved value. Omitting\n``api_key`` keeps the stored key, ``params`` keys you don't send are\npreserved, and omitting ``fallback_enabled`` leaves the flag alone\n(``false`` on a new row). The merged result — not the partial input —\nis validated against the layer's schema (422 on a mismatch). 404 on an\nunknown layer.",
        "operationId": "upsert_provider",
        "parameters": [
          {
            "name": "layer",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Layer"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderConfigUpsert"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderConfigEntry"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/providers/{layer}/{provider}": {
      "delete": {
        "tags": [
          "providers"
        ],
        "summary": "Delete Provider",
        "description": "Delete one provider row. Deleting the active row promotes the\nmost-recently-updated sibling. Idempotent: deleting a row that isn't\nthere is a 204 too. 404 on an unknown layer.",
        "operationId": "delete_provider",
        "parameters": [
          {
            "name": "layer",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Layer"
            }
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Provider"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/providers/{layer}/activate": {
      "post": {
        "tags": [
          "providers"
        ],
        "summary": "Activate Provider",
        "description": "Switch which saved provider is active for ``layer``. 404 when that\nprovider has no saved config.",
        "operationId": "activate_provider",
        "parameters": [
          {
            "name": "layer",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Layer"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderActivateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderConfigEntry"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/providers/{layer}/validate": {
      "post": {
        "tags": [
          "providers"
        ],
        "summary": "Validate Provider",
        "description": "Probe a provider key against the real provider.\n\nEmpty body tests the layer's active provider with its stored key; send\n``provider`` to test a specific saved row, or ``api_key`` (plus\n``provider``/``params``) to test a key before saving it.",
        "operationId": "validate_provider",
        "parameters": [
          {
            "name": "layer",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Layer"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderValidateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderValidateResult"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "description": "The request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/healthz": {
      "get": {
        "summary": "Healthz",
        "description": "Liveness check. Returns {\"status\": \"ok\"} with no auth required.",
        "operationId": "healthz_healthz_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": {
                    "type": "string"
                  },
                  "type": "object",
                  "title": "Response Healthz Healthz Get"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Body_upload_email_attachment": {
        "properties": {
          "file": {
            "type": "string",
            "contentMediaType": "application/octet-stream",
            "title": "File",
            "description": "The file to upload, as multipart/form-data. Size-limited; an oversize upload is rejected with 422."
          }
        },
        "type": "object",
        "required": [
          "file"
        ],
        "title": "Body_upload_email_attachment"
      },
      "CallCreate": {
        "properties": {
          "recipient_consent": {
            "type": "boolean",
            "title": "Recipient Consent",
            "description": "Attestation that you have obtained the lawful consent required to contact this recipient. Hail does not verify consent itself — you are responsible for a lawful basis under TCPA/ePrivacy/PECR/CAN-SPAM/GDPR as applicable. Rejected (422) if not true."
          },
          "consent_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consent Source",
            "description": "Where/how consent was obtained (e.g. 'signup form', 'prior customer relationship'). Required (non-empty) when message_type is 'marketing'."
          },
          "consent_obtained_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consent Obtained At",
            "description": "When consent was obtained, if known."
          },
          "message_type": {
            "type": "string",
            "enum": [
              "marketing",
              "informational"
            ],
            "title": "Message Type",
            "description": "'marketing' additionally requires a non-empty consent_source. Use 'informational' for transactional/service communications.",
            "default": "informational"
          },
          "to": {
            "type": "string",
            "title": "To",
            "description": "Recipient phone number, E.164 format (e.g. +14155551234)."
          },
          "from": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "From",
            "description": "Caller-id phone number, E.164 format. Must be a number owned by the organization with the voice capability. Omitted: an active org-owned number is used if one exists, else a number is claimed from the shared pool."
          },
          "system_prompt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "System Prompt",
            "description": "Task instructions for the agent, sent as its leading system message. At least one of system_prompt or llm is required; both together is also valid."
          },
          "llm": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/LLMConfig"
              },
              {
                "type": "null"
              }
            ],
            "description": "BYO LLM endpoint the call runs on instead of Hail's default model. At least one of system_prompt or llm is required; both together is also valid."
          },
          "first_message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "First Message",
            "description": "Opening line the agent speaks first. Omitted: the agent waits for the callee to speak first."
          },
          "ai_disclosure": {
            "type": "boolean",
            "title": "Ai Disclosure",
            "description": "Speak the AI self-disclosure line ('Hi, this is an AI assistant calling on behalf of ...') as the first thing on the call. Enabled by default. Disable only if you have verified the disclosure is not required for this call — 47 CFR 64.1200(b)(1) requires identifying the initiating business at the start of artificial-voice calls in the US, and several jurisdictions have AI bot-disclosure laws. Hail does not verify this for you. The agent still identifies itself as an AI if asked.",
            "default": true
          },
          "voice_config": {
            "$ref": "#/components/schemas/VoiceConfig",
            "description": "TTS voice, VAD, turn-detection, and spoken-language settings for this call."
          },
          "conversation_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Conversation Id",
            "description": "Groups this call with other calls/emails/SMS into one conversation thread. Omitted: the call is not linked to a conversation."
          },
          "metadata": {
            "additionalProperties": true,
            "type": "object",
            "title": "Metadata",
            "description": "Free-form JSON object attached to the call and echoed back on reads. Not interpreted by Hail."
          },
          "tools": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tools",
            "description": "Agent tools to allow on this call. Omitted: every tool the organization's configured channels support (new channels appear automatically). Empty list: no tools. Tool names are validated against the server's registry."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "recipient_consent",
          "to"
        ],
        "title": "CallCreate"
      },
      "CallListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/CallResponse"
            },
            "type": "array",
            "title": "Items",
            "description": "Calls in this page, newest first."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "CallListResponse"
      },
      "CallResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this call."
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "title": "Organization Id",
            "description": "Organization that placed or received this call."
          },
          "conversation_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Conversation Id",
            "description": "Conversation thread this call is grouped into, if any. Null when the call was not linked to a conversation."
          },
          "from_e164": {
            "type": "string",
            "title": "From E164",
            "description": "Caller-id phone number used, E.164 format."
          },
          "to_e164": {
            "type": "string",
            "title": "To E164",
            "description": "Recipient phone number, E.164 format."
          },
          "direction": {
            "type": "string",
            "enum": [
              "outbound",
              "inbound"
            ],
            "title": "Direction",
            "description": "'outbound' for calls Hail placed, 'inbound' for calls received."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "dialing",
              "ringing",
              "in_progress",
              "completed",
              "failed",
              "busy",
              "no_answer",
              "canceled"
            ],
            "title": "Status",
            "description": "Current call-progress state: 'queued', 'dialing', 'ringing', 'in_progress', or one of the terminal states 'completed', 'failed', 'busy', 'no_answer', 'canceled'."
          },
          "end_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "End Reason",
            "description": "Machine-readable reason the call reached a terminal status (e.g. 'normal_hangup', 'user_rejected', 'sip_trunk_failure'). Null while the call is still in progress."
          },
          "provider_call_sid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider Call Sid",
            "description": "The telephony provider's identifier for this call leg, if assigned."
          },
          "livekit_room": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Livekit Room",
            "description": "Name of the LiveKit room hosting this call's media session, if one was created."
          },
          "initial_prompt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Initial Prompt",
            "description": "The system_prompt this call was created with, if any."
          },
          "recording_s3_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recording S3 Key",
            "description": "Internal storage key for the call recording. Not a directly fetchable URL."
          },
          "requested_at": {
            "type": "string",
            "format": "date-time",
            "title": "Requested At",
            "description": "When the call was requested, ISO 8601 timestamp."
          },
          "started_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Started At",
            "description": "When dialing began, ISO 8601 timestamp. Null until the call starts."
          },
          "answered_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Answered At",
            "description": "When the callee answered, ISO 8601 timestamp. Null if never answered."
          },
          "ended_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ended At",
            "description": "When the call ended, ISO 8601 timestamp. Null while still in progress."
          }
        },
        "type": "object",
        "required": [
          "id",
          "organization_id",
          "conversation_id",
          "from_e164",
          "to_e164",
          "direction",
          "status",
          "end_reason",
          "provider_call_sid",
          "livekit_room",
          "initial_prompt",
          "recording_s3_key",
          "requested_at",
          "started_at",
          "answered_at",
          "ended_at"
        ],
        "title": "CallResponse"
      },
      "ContactCreate": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Name",
            "description": "Display name for the contact."
          },
          "phone_e164": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone E164",
            "description": "Phone number, E.164 format. At least one of phone_e164 or email is required."
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Email address, stored lowercased. At least one of phone_e164 or email is required."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "name"
        ],
        "title": "ContactCreate"
      },
      "ContactEntry": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "'member:<user_id>' for an org member, or the contact row's UUID (as a string) for a manual contact."
          },
          "kind": {
            "type": "string",
            "enum": [
              "member",
              "manual"
            ],
            "title": "Kind",
            "description": "'member' if this row is a member of the organization, 'manual' if it was added as a contact."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Display name."
          },
          "phone_e164": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone E164",
            "description": "Phone number, E.164 format. Null if none on file."
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Email address. Null if none on file."
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Role",
            "description": "Organization role (e.g. 'owner', 'admin', 'member') for kind='member'. Always null for kind='manual'."
          }
        },
        "type": "object",
        "required": [
          "id",
          "kind",
          "name"
        ],
        "title": "ContactEntry",
        "description": "One row in the computed contacts union — an org member or a manual\ncontact. ``id`` is ``member:<user_id>`` for members, the contact row's\nUUID (as str) for manual rows."
      },
      "ContactListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/ContactEntry"
            },
            "type": "array",
            "title": "Items",
            "description": "Contacts in this page."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "ContactListResponse"
      },
      "ContactPatch": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "New display name. Omit to leave unchanged; cannot be set to null."
          },
          "phone_e164": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone E164",
            "description": "New phone number, E.164 format. Omit to leave unchanged; explicit null clears it. The contact must keep at least one of phone_e164 or email."
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "New email address, stored lowercased. Omit to leave unchanged; explicit null clears it. The contact must keep at least one of phone_e164 or email."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "ContactPatch"
      },
      "DnsRecordSchema": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "DNS record name/host to publish (e.g. a CNAME's subdomain)."
          },
          "value": {
            "type": "string",
            "title": "Value",
            "description": "DNS record value to publish (e.g. a CNAME target or TXT content)."
          },
          "type": {
            "type": "string",
            "enum": [
              "CNAME",
              "MX",
              "TXT"
            ],
            "title": "Type",
            "description": "DNS record type: 'CNAME' (DKIM), 'MX' (MAIL FROM), or 'TXT' (SPF).",
            "default": "CNAME"
          },
          "priority": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Priority",
            "description": "MX priority. Only present for type='MX'; null otherwise."
          }
        },
        "additionalProperties": true,
        "type": "object",
        "required": [
          "name",
          "value"
        ],
        "title": "DnsRecordSchema",
        "description": "One DNS record the tenant must publish for a sending domain.\n\nCovers DKIM CNAMEs, MAIL FROM MX, and SPF TXT records."
      },
      "DomainCheckResponse": {
        "properties": {
          "domain": {
            "type": "string",
            "title": "Domain",
            "description": "The apex domain that was checked, lowercased."
          },
          "in_use": {
            "type": "boolean",
            "title": "In Use",
            "description": "True if the domain already has MX records — it receives mail elsewhere."
          },
          "existing_mx": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Existing Mx",
            "description": "MX hostnames currently published for the domain. Empty when in_use is false."
          },
          "suggested_domain": {
            "type": "string",
            "title": "Suggested Domain",
            "description": "Domain to use for a custom sending identity: the apex domain if it is not already receiving mail, or an 'inbox.' subdomain if it is (so setup doesn't collide with existing mail)."
          }
        },
        "type": "object",
        "required": [
          "domain",
          "in_use",
          "existing_mx",
          "suggested_domain"
        ],
        "title": "DomainCheckResponse"
      },
      "EmailAttachmentResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this attachment."
          },
          "filename": {
            "type": "string",
            "title": "Filename",
            "description": "Original filename of the attachment."
          },
          "content_type": {
            "type": "string",
            "title": "Content Type",
            "description": "MIME type of the attachment."
          },
          "size_bytes": {
            "type": "integer",
            "title": "Size Bytes",
            "description": "Size of the attachment in bytes."
          },
          "content_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Content Id",
            "description": "MIME Content-ID, present when this attachment is referenced inline (cid:) from the HTML body. Null otherwise."
          },
          "url": {
            "type": "string",
            "title": "Url",
            "description": "API endpoint that 302-redirects to a presigned download URL for this attachment."
          }
        },
        "type": "object",
        "required": [
          "id",
          "filename",
          "content_type",
          "size_bytes",
          "url"
        ],
        "title": "EmailAttachmentResponse",
        "description": "One inbound MIME attachment as exposed to API consumers.\n\n``url`` is the stable Hail API endpoint that 302-redirects to a\npresigned S3 URL on access — see GET /emails/{id}/attachments/{aid}."
      },
      "EmailAttachmentUploadResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Reusable attachment id — pass it in EmailCreate.attachment_ids to attach it to a send."
          },
          "filename": {
            "type": "string",
            "title": "Filename",
            "description": "Original filename of the uploaded file."
          },
          "content_type": {
            "type": "string",
            "title": "Content Type",
            "description": "MIME type of the uploaded file."
          },
          "size_bytes": {
            "type": "integer",
            "title": "Size Bytes",
            "description": "Size of the uploaded file in bytes."
          }
        },
        "type": "object",
        "required": [
          "id",
          "filename",
          "content_type",
          "size_bytes"
        ],
        "title": "EmailAttachmentUploadResponse",
        "description": "Returned by POST /email-attachments.\n\n``id`` is reusable across many ``POST /emails`` calls via\n``EmailCreate.attachment_ids`` until Hail garbage-collects it (24h\nif never referenced by a send)."
      },
      "EmailCreate": {
        "properties": {
          "recipient_consent": {
            "type": "boolean",
            "title": "Recipient Consent",
            "description": "Attestation that you have obtained the lawful consent required to contact this recipient. Hail does not verify consent itself — you are responsible for a lawful basis under TCPA/ePrivacy/PECR/CAN-SPAM/GDPR as applicable. Rejected (422) if not true."
          },
          "consent_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consent Source",
            "description": "Where/how consent was obtained (e.g. 'signup form', 'prior customer relationship'). Required (non-empty) when message_type is 'marketing'."
          },
          "consent_obtained_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consent Obtained At",
            "description": "When consent was obtained, if known."
          },
          "message_type": {
            "type": "string",
            "enum": [
              "marketing",
              "informational"
            ],
            "title": "Message Type",
            "description": "'marketing' additionally requires a non-empty consent_source. Use 'informational' for transactional/service communications.",
            "default": "informational"
          },
          "from": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "From",
            "description": "Sender email address. Must be a verified identity on the organization's email domains. Omitted: the org's resolved default sending address, if one exists."
          },
          "from_name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 256
              },
              {
                "type": "null"
              }
            ],
            "title": "From Name",
            "description": "Display name for the From: header (e.g. 'Acme Billing'). Omitted: no display name."
          },
          "to": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "minItems": 1,
            "title": "To",
            "description": "Recipient email addresses. At least one required."
          },
          "cc": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cc",
            "description": "CC recipient email addresses."
          },
          "bcc": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bcc",
            "description": "BCC recipient email addresses."
          },
          "reply_to": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reply To",
            "description": "Reply-To email address. Omitted: replies go to the From address."
          },
          "subject": {
            "type": "string",
            "maxLength": 998,
            "minLength": 1,
            "title": "Subject",
            "description": "Email subject line."
          },
          "body_text": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Body Text",
            "description": "Plain-text body. Either body_text or body_html (or both) is required. A plain-text-only email cannot be tracked for opens or clicks; include body_html to get those events."
          },
          "body_html": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Body Html",
            "description": "HTML body. Either body_text or body_html (or both) is required. Prefer including body_html: open and click tracking only works for emails with an HTML body. Plain-text-only emails still get sent, delivered, and bounce events, but opens and clicks are never tracked."
          },
          "conversation_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Conversation Id",
            "description": "Groups this email with other calls/emails/SMS into one conversation thread. Omitted: the email is not linked to a conversation."
          },
          "metadata": {
            "additionalProperties": true,
            "type": "object",
            "title": "Metadata",
            "description": "Free-form JSON object attached to the email and echoed back on reads. Not interpreted by Hail."
          },
          "attachment_ids": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "format": "uuid"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Attachment Ids",
            "description": "Ids returned by POST /email-attachments to attach to this send. Omitted: no attachments."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "recipient_consent",
          "to",
          "subject"
        ],
        "title": "EmailCreate"
      },
      "EmailDomainCreate": {
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "hail_mail",
              "custom"
            ],
            "title": "Kind",
            "description": "'hail_mail' for a Hail-hosted address (domain omitted, composed from the prefix fields), or 'custom' to send from your own domain (domain required, prefix fields omitted)."
          },
          "domain": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Domain",
            "description": "DNS domain to send from (e.g. 'acme.com'). Required for kind='custom'; must be omitted for kind='hail_mail'."
          },
          "local_prefix_user": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Local Prefix User",
            "description": "User-chosen local-part prefix for a hail_mail address. Only valid for kind='hail_mail'. Falls back to HAIL_MAIL_DEFAULT_USER_PREFIX if omitted."
          },
          "local_prefix_org": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Local Prefix Org",
            "description": "Org-chosen local-part prefix for a hail_mail address. Only valid for kind='hail_mail'. Falls back to HAIL_MAIL_DEFAULT_ORG_PREFIX if omitted."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "kind"
        ],
        "title": "EmailDomainCreate",
        "description": "Request body for POST /email-domains.\n\nFor ``kind='hail_mail'`` ``domain`` is omitted; the server composes\nthe full address as ``<local_prefix_user>+<local_prefix_org>@<base>``.\nBoth prefixes are optional in the body and fall back to the\n``HAIL_MAIL_DEFAULT_*_PREFIX`` env vars; the server returns 503 if\nneither is supplied. For ``kind='custom'`` ``domain`` is required and\nthe prefix fields must be omitted."
      },
      "EmailDomainListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/EmailDomainResponse"
            },
            "type": "array",
            "title": "Items",
            "description": "Email domains in this page."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          },
          "default_from": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Default From",
            "description": "The From address used when a send omits 'from'. Null when no such default can be resolved (e.g. multiple verified identities, or none that can send yet). Computed across the whole organization, not just this page."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "EmailDomainListResponse"
      },
      "EmailDomainPatch": {
        "properties": {
          "local_prefix_user": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Local Prefix User",
            "description": "New user local-part prefix. Only valid on kind='hail_mail' rows. Omit to leave unchanged."
          },
          "local_prefix_org": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Local Prefix Org",
            "description": "New org local-part prefix. Only valid on kind='hail_mail' rows. Omit to leave unchanged."
          },
          "inbound_enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Inbound Enabled",
            "description": "Whether to accept inbound mail on this domain. Requires forward_to (or an existing one) when true. Omit to leave unchanged."
          },
          "forward_to": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Forward To",
            "description": "Email addresses to forward inbound mail to. Omit to leave unchanged."
          },
          "forward_rate_per_hour": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Forward Rate Per Hour",
            "description": "Cap on forwarded messages per hour. Omit to leave unchanged."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "EmailDomainPatch",
        "description": "Body for PATCH /email-domains/{id}.\n\nTwo clusters of mutable fields:\n\n* Hail-mail addressing — the user/org prefix pair (only valid on\n  ``kind='hail_mail'`` rows; the handler returns 422 if a tenant tries\n  to PATCH these on a custom row).\n* Inbound action — ``inbound_enabled`` + ``forward_to`` + the optional\n  ``forward_rate_per_hour`` cap. These apply to either kind, but this\n  milestone routes inbound only to ``hail_mail`` rows; custom-domain\n  inbound (MX delegation) is the next milestone.\n\nEvery field is independently optional so ``PATCH`` semantics work the\nway callers expect: send only what you want to change. The route\nenforces the cross-field rules (the CHECK constraint on the table\nrequires an action when ``inbound_enabled`` is true) — we don't\nre-implement it here because the patch may merge with existing row\nstate to satisfy the invariant."
      },
      "EmailDomainResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this email domain."
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "title": "Organization Id",
            "description": "Organization that owns this domain."
          },
          "kind": {
            "type": "string",
            "enum": [
              "hail_mail",
              "custom"
            ],
            "title": "Kind",
            "description": "'hail_mail' (Hail-hosted address) or 'custom' (your own domain)."
          },
          "domain": {
            "type": "string",
            "title": "Domain",
            "description": "The DNS domain mail is sent from."
          },
          "local_prefix_user": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Local Prefix User",
            "description": "User local-part prefix for a hail_mail address. Null for kind='custom'."
          },
          "local_prefix_org": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Local Prefix Org",
            "description": "Org local-part prefix for a hail_mail address. Null for kind='custom'."
          },
          "verification_status": {
            "type": "string",
            "enum": [
              "pending",
              "verified",
              "failed"
            ],
            "title": "Verification Status",
            "description": "'pending' (not yet verified), 'verified' (ready to send), or 'failed'."
          },
          "dns_records": {
            "items": {
              "$ref": "#/components/schemas/DnsRecordSchema"
            },
            "type": "array",
            "title": "Dns Records",
            "description": "DNS records (DKIM, MAIL FROM MX, SPF) the tenant must publish to verify this domain."
          },
          "mail_from_domain": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mail From Domain",
            "description": "Custom MAIL FROM domain, if configured. Null when using the provider default."
          },
          "mail_from_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mail From Status",
            "description": "Verification status of the custom MAIL FROM domain, if one is configured. Secondary to verification_status."
          },
          "provider": {
            "type": "string",
            "title": "Provider",
            "description": "Email sending provider for this domain (currently always 'ses')."
          },
          "verified_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Verified At",
            "description": "When the domain became verified, ISO 8601 timestamp. Null until it is."
          },
          "inbound_enabled": {
            "type": "boolean",
            "title": "Inbound Enabled",
            "description": "Whether this domain accepts and forwards inbound mail.",
            "default": false
          },
          "forward_to": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Forward To",
            "description": "Email addresses inbound mail is forwarded to, if inbound is enabled."
          },
          "forward_rate_per_hour": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Forward Rate Per Hour",
            "description": "Configured cap on forwarded messages per hour, if set."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "When this domain was added, ISO 8601 timestamp."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "title": "Updated At",
            "description": "When this domain was last modified, ISO 8601 timestamp."
          },
          "receive_ready": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receive Ready",
            "description": "True when the domain's published MX points at Hail's inbound host. Only populated by POST /{id}/verify on custom domains; null everywhere else."
          }
        },
        "type": "object",
        "required": [
          "id",
          "organization_id",
          "kind",
          "domain",
          "local_prefix_user",
          "local_prefix_org",
          "verification_status",
          "dns_records",
          "mail_from_domain",
          "provider",
          "verified_at",
          "created_at",
          "updated_at"
        ],
        "title": "EmailDomainResponse",
        "description": "Read view for an email domain.\n\nThe inbound-action fields (``inbound_enabled``, ``forward_to``,\n``forward_rate_per_hour``) surface what the row has configured for\nincoming mail."
      },
      "EmailEventListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/EmailEventResponse"
            },
            "type": "array",
            "title": "Items",
            "description": "Events for this email, oldest first."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "EmailEventListResponse"
      },
      "EmailEventResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this event."
          },
          "email_id": {
            "type": "string",
            "format": "uuid",
            "title": "Email Id",
            "description": "The email this event belongs to."
          },
          "kind": {
            "type": "string",
            "enum": [
              "sent",
              "delivered",
              "delivery_delayed",
              "bounced",
              "complained",
              "rejected",
              "opened",
              "clicked"
            ],
            "title": "Kind",
            "description": "Event kind: 'sent', 'delivered', 'delivery_delayed', 'bounced', 'complained', 'rejected', 'opened', or 'clicked'. 'opened' and 'clicked' only occur for emails sent with an HTML body; plain-text-only emails never produce them."
          },
          "payload": {
            "additionalProperties": true,
            "type": "object",
            "title": "Payload",
            "description": "Event-kind-specific detail, as a free-form JSON object."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "title": "Occurred At",
            "description": "When this event occurred, ISO 8601 timestamp."
          }
        },
        "type": "object",
        "required": [
          "id",
          "email_id",
          "kind",
          "payload",
          "occurred_at"
        ],
        "title": "EmailEventResponse"
      },
      "EmailListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/EmailSummary"
            },
            "type": "array",
            "title": "Items",
            "description": "Emails in this page, newest first."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "EmailListResponse"
      },
      "EmailResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this email."
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "title": "Organization Id",
            "description": "Organization that sent or received this email."
          },
          "conversation_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Conversation Id",
            "description": "Conversation thread this email is grouped into, if any. Null when it was not linked to a conversation."
          },
          "email_domain_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email Domain Id",
            "description": "The sending domain used, if from_address belongs to one of the org's configured domains."
          },
          "direction": {
            "type": "string",
            "enum": [
              "outbound",
              "inbound"
            ],
            "title": "Direction",
            "description": "'outbound' for emails Hail sent, 'inbound' for emails received.",
            "default": "outbound"
          },
          "from_address": {
            "type": "string",
            "title": "From Address",
            "description": "Sender email address."
          },
          "from_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "From Name",
            "description": "Display name used on the From: header, when the sender supplied one. Always null on inbound rows."
          },
          "to_addresses": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "To Addresses",
            "description": "Recipient email addresses."
          },
          "cc_addresses": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cc Addresses",
            "description": "CC recipient email addresses, if any."
          },
          "bcc_addresses": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bcc Addresses",
            "description": "BCC recipient email addresses, if any."
          },
          "reply_to": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reply To",
            "description": "Reply-To email address, if set."
          },
          "subject": {
            "type": "string",
            "title": "Subject",
            "description": "Email subject line."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "sent",
              "delivered",
              "failed",
              "bounced",
              "complained",
              "received"
            ],
            "title": "Status",
            "description": "Delivery status: 'queued', 'sent', 'delivered', 'failed', 'bounced', 'complained', or 'received' (inbound emails)."
          },
          "end_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "End Reason",
            "description": "Reason delivery failed or bounced, if applicable. Null on success or while pending."
          },
          "provider_message_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider Message Id",
            "description": "The email provider's identifier for this message, if assigned."
          },
          "requested_at": {
            "type": "string",
            "format": "date-time",
            "title": "Requested At",
            "description": "When the send was requested, ISO 8601 timestamp."
          },
          "sent_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sent At",
            "description": "When the message was handed to the provider, ISO 8601 timestamp. Null until sent."
          },
          "failed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Failed At",
            "description": "When the send failed, ISO 8601 timestamp. Null unless it failed."
          },
          "metadata": {
            "additionalProperties": true,
            "type": "object",
            "title": "Metadata",
            "description": "Free-form JSON object attached to the email, as sent on create. Not interpreted by Hail."
          },
          "body_text": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Body Text",
            "description": "Plain-text body, if any."
          },
          "body_html": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Body Html",
            "description": "HTML body, if any."
          },
          "message_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message Id",
            "description": "RFC 5322 Message-ID header. Inbound emails only; null on outbound rows."
          },
          "in_reply_to": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "In Reply To",
            "description": "RFC 5322 In-Reply-To header. Inbound emails only; null on outbound rows."
          },
          "references_ids": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "References Ids",
            "description": "RFC 5322 References header, split into ids. Inbound emails only; null on outbound rows."
          },
          "spam_verdict": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Spam Verdict",
            "description": "Provider spam-scan verdict (e.g. 'PASS'/'FAIL'). Inbound emails only; null on outbound rows."
          },
          "virus_verdict": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Virus Verdict",
            "description": "Provider virus-scan verdict (e.g. 'PASS'/'FAIL'). Inbound emails only; null on outbound rows."
          },
          "dkim_verdict": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dkim Verdict",
            "description": "Provider DKIM-authentication verdict (e.g. 'PASS'/'FAIL'). Inbound emails only; null on outbound rows."
          },
          "spf_verdict": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Spf Verdict",
            "description": "Provider SPF-authentication verdict (e.g. 'PASS'/'FAIL'). Inbound emails only; null on outbound rows."
          },
          "dmarc_verdict": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dmarc Verdict",
            "description": "Provider DMARC-authentication verdict (e.g. 'PASS'/'FAIL'). Inbound emails only; null on outbound rows."
          },
          "provider_received_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider Received At",
            "description": "When the provider received this email, ISO 8601 timestamp. Inbound emails only."
          },
          "raw_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Raw Url",
            "description": "API endpoint that redirects to the original MIME blob. Inbound emails only; null on outbound rows."
          },
          "attachments": {
            "items": {
              "$ref": "#/components/schemas/EmailAttachmentResponse"
            },
            "type": "array",
            "title": "Attachments",
            "description": "Inbound MIME attachments on this email. Empty on outbound rows.",
            "default": []
          },
          "last_event_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Event At",
            "description": "When the most recent delivery event for this email occurred, ISO 8601 timestamp."
          }
        },
        "type": "object",
        "required": [
          "id",
          "organization_id",
          "conversation_id",
          "email_domain_id",
          "from_address",
          "to_addresses",
          "cc_addresses",
          "bcc_addresses",
          "reply_to",
          "subject",
          "status",
          "end_reason",
          "provider_message_id",
          "requested_at",
          "sent_at",
          "failed_at",
          "body_text",
          "body_html"
        ],
        "title": "EmailResponse"
      },
      "EmailStatsBucket": {
        "properties": {
          "sent": {
            "type": "integer",
            "title": "Sent",
            "description": "Emails sent in the window.",
            "default": 0
          },
          "delivered": {
            "type": "integer",
            "title": "Delivered",
            "description": "Emails confirmed delivered in the window.",
            "default": 0
          },
          "delivery_delayed": {
            "type": "integer",
            "title": "Delivery Delayed",
            "description": "Emails with a delivery-delayed event in the window.",
            "default": 0
          },
          "bounced": {
            "type": "integer",
            "title": "Bounced",
            "description": "Emails bounced (soft or hard) in the window.",
            "default": 0
          },
          "bounced_hard": {
            "type": "integer",
            "title": "Bounced Hard",
            "description": "Emails hard-bounced in the window. Subset of bounced.",
            "default": 0
          },
          "complained": {
            "type": "integer",
            "title": "Complained",
            "description": "Emails that received a spam complaint in the window.",
            "default": 0
          },
          "rejected": {
            "type": "integer",
            "title": "Rejected",
            "description": "Emails rejected by the provider before sending, in the window.",
            "default": 0
          },
          "opened": {
            "type": "integer",
            "title": "Opened",
            "description": "Total open events in the window, including repeat opens by the same recipient. HTML emails only; plain-text-only emails are never tracked for opens.",
            "default": 0
          },
          "clicked": {
            "type": "integer",
            "title": "Clicked",
            "description": "Total click events in the window, including repeat clicks by the same recipient. HTML emails only; plain-text-only emails are never tracked for clicks.",
            "default": 0
          },
          "unique_opened": {
            "type": "integer",
            "title": "Unique Opened",
            "description": "Distinct emails opened at least once in the window (HTML emails only).",
            "default": 0
          },
          "unique_clicked": {
            "type": "integer",
            "title": "Unique Clicked",
            "description": "Distinct emails clicked at least once in the window (HTML emails only).",
            "default": 0
          },
          "bucket_start": {
            "type": "string",
            "format": "date-time",
            "title": "Bucket Start",
            "description": "Start of this bucket, ISO 8601 timestamp."
          }
        },
        "type": "object",
        "required": [
          "bucket_start"
        ],
        "title": "EmailStatsBucket"
      },
      "EmailStatsCounts": {
        "properties": {
          "sent": {
            "type": "integer",
            "title": "Sent",
            "description": "Emails sent in the window.",
            "default": 0
          },
          "delivered": {
            "type": "integer",
            "title": "Delivered",
            "description": "Emails confirmed delivered in the window.",
            "default": 0
          },
          "delivery_delayed": {
            "type": "integer",
            "title": "Delivery Delayed",
            "description": "Emails with a delivery-delayed event in the window.",
            "default": 0
          },
          "bounced": {
            "type": "integer",
            "title": "Bounced",
            "description": "Emails bounced (soft or hard) in the window.",
            "default": 0
          },
          "bounced_hard": {
            "type": "integer",
            "title": "Bounced Hard",
            "description": "Emails hard-bounced in the window. Subset of bounced.",
            "default": 0
          },
          "complained": {
            "type": "integer",
            "title": "Complained",
            "description": "Emails that received a spam complaint in the window.",
            "default": 0
          },
          "rejected": {
            "type": "integer",
            "title": "Rejected",
            "description": "Emails rejected by the provider before sending, in the window.",
            "default": 0
          },
          "opened": {
            "type": "integer",
            "title": "Opened",
            "description": "Total open events in the window, including repeat opens by the same recipient. HTML emails only; plain-text-only emails are never tracked for opens.",
            "default": 0
          },
          "clicked": {
            "type": "integer",
            "title": "Clicked",
            "description": "Total click events in the window, including repeat clicks by the same recipient. HTML emails only; plain-text-only emails are never tracked for clicks.",
            "default": 0
          },
          "unique_opened": {
            "type": "integer",
            "title": "Unique Opened",
            "description": "Distinct emails opened at least once in the window (HTML emails only).",
            "default": 0
          },
          "unique_clicked": {
            "type": "integer",
            "title": "Unique Clicked",
            "description": "Distinct emails clicked at least once in the window (HTML emails only).",
            "default": 0
          }
        },
        "type": "object",
        "title": "EmailStatsCounts"
      },
      "EmailStatsRates": {
        "properties": {
          "delivery": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Delivery",
            "description": "delivered / sent for the window. Null when sent == 0."
          },
          "bounce": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bounce",
            "description": "bounced_hard / sent for the window. Null when sent == 0."
          },
          "complaint": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Complaint",
            "description": "complained / sent for the window. Null when sent == 0."
          },
          "open": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Open",
            "description": "unique_opened / sent for the window. Null when sent == 0. Only HTML emails can be opened-tracked, so plain-text sends lower this rate."
          },
          "click": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Click",
            "description": "unique_clicked / sent for the window. Null when sent == 0. Only HTML emails can be click-tracked, so plain-text sends lower this rate."
          }
        },
        "type": "object",
        "title": "EmailStatsRates",
        "description": "All None when sent == 0 in the window."
      },
      "EmailStatsResponse": {
        "properties": {
          "from": {
            "type": "string",
            "format": "date-time",
            "title": "From",
            "description": "Start of the queried window, ISO 8601 timestamp (inclusive)."
          },
          "to": {
            "type": "string",
            "format": "date-time",
            "title": "To",
            "description": "End of the queried window, ISO 8601 timestamp (exclusive)."
          },
          "bucket": {
            "type": "string",
            "enum": [
              "hour",
              "day"
            ],
            "title": "Bucket",
            "description": "Time-bucket size used for the series."
          },
          "totals": {
            "$ref": "#/components/schemas/EmailStatsCounts",
            "description": "Event counts summed across the whole window."
          },
          "rates": {
            "$ref": "#/components/schemas/EmailStatsRates",
            "description": "Derived rates (delivery, bounce, complaint, open, click) for the whole window. Each individual rate is null when sent == 0."
          },
          "series": {
            "items": {
              "$ref": "#/components/schemas/EmailStatsBucket"
            },
            "type": "array",
            "title": "Series",
            "description": "Per-bucket event counts across the window, in chronological order."
          }
        },
        "type": "object",
        "required": [
          "from",
          "to",
          "bucket",
          "totals",
          "rates",
          "series"
        ],
        "title": "EmailStatsResponse"
      },
      "EmailSummary": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this email."
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "title": "Organization Id",
            "description": "Organization that sent or received this email."
          },
          "conversation_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Conversation Id",
            "description": "Conversation thread this email is grouped into, if any. Null when it was not linked to a conversation."
          },
          "email_domain_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email Domain Id",
            "description": "The sending domain used, if from_address belongs to one of the org's configured domains."
          },
          "direction": {
            "type": "string",
            "enum": [
              "outbound",
              "inbound"
            ],
            "title": "Direction",
            "description": "'outbound' for emails Hail sent, 'inbound' for emails received.",
            "default": "outbound"
          },
          "from_address": {
            "type": "string",
            "title": "From Address",
            "description": "Sender email address."
          },
          "from_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "From Name",
            "description": "Display name used on the From: header, when the sender supplied one. Always null on inbound rows."
          },
          "to_addresses": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "To Addresses",
            "description": "Recipient email addresses."
          },
          "cc_addresses": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cc Addresses",
            "description": "CC recipient email addresses, if any."
          },
          "bcc_addresses": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bcc Addresses",
            "description": "BCC recipient email addresses, if any."
          },
          "reply_to": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reply To",
            "description": "Reply-To email address, if set."
          },
          "subject": {
            "type": "string",
            "title": "Subject",
            "description": "Email subject line."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "sent",
              "delivered",
              "failed",
              "bounced",
              "complained",
              "received"
            ],
            "title": "Status",
            "description": "Delivery status: 'queued', 'sent', 'delivered', 'failed', 'bounced', 'complained', or 'received' (inbound emails)."
          },
          "end_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "End Reason",
            "description": "Reason delivery failed or bounced, if applicable. Null on success or while pending."
          },
          "provider_message_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider Message Id",
            "description": "The email provider's identifier for this message, if assigned."
          },
          "requested_at": {
            "type": "string",
            "format": "date-time",
            "title": "Requested At",
            "description": "When the send was requested, ISO 8601 timestamp."
          },
          "sent_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sent At",
            "description": "When the message was handed to the provider, ISO 8601 timestamp. Null until sent."
          },
          "failed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Failed At",
            "description": "When the send failed, ISO 8601 timestamp. Null unless it failed."
          },
          "metadata": {
            "additionalProperties": true,
            "type": "object",
            "title": "Metadata",
            "description": "Free-form JSON object attached to the email, as sent on create. Not interpreted by Hail."
          }
        },
        "type": "object",
        "required": [
          "id",
          "organization_id",
          "conversation_id",
          "email_domain_id",
          "from_address",
          "to_addresses",
          "cc_addresses",
          "bcc_addresses",
          "reply_to",
          "subject",
          "status",
          "end_reason",
          "provider_message_id",
          "requested_at",
          "sent_at",
          "failed_at"
        ],
        "title": "EmailSummary",
        "description": "Trimmed view for list endpoints — drops the message bodies.\n\nBodies can be large and contain PII; paging through a year of mail\nshouldn't return every byte of every message just to render a list.\nUse ``EmailResponse`` (via ``GET /emails/{id}``) for the full row."
      },
      "EventResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this event."
          },
          "source": {
            "type": "string",
            "enum": [
              "call",
              "email",
              "sms"
            ],
            "title": "Source",
            "description": "Which channel this event belongs to: 'call', 'email', or 'sms'."
          },
          "call_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Call Id",
            "description": "The call this event belongs to. Set only when source='call'."
          },
          "email_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email Id",
            "description": "The email this event belongs to. Set only when source='email'."
          },
          "sms_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sms Id",
            "description": "The message this event belongs to. Set only when source='sms'."
          },
          "kind": {
            "type": "string",
            "title": "Kind",
            "description": "Event kind within the source (e.g. 'queued', 'delivered', 'bounced'). Vocabulary differs per source."
          },
          "payload": {
            "additionalProperties": true,
            "type": "object",
            "title": "Payload",
            "description": "Event-kind-specific detail, as a free-form JSON object."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "title": "Occurred At",
            "description": "When this event occurred, ISO 8601 timestamp."
          }
        },
        "type": "object",
        "required": [
          "id",
          "source",
          "kind",
          "payload",
          "occurred_at"
        ],
        "title": "EventResponse",
        "description": "One event on the unified GET /events stream (call, email, or SMS)."
      },
      "EventStreamResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/EventResponse"
            },
            "type": "array",
            "title": "Items",
            "description": "Events in this page, oldest first."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          },
          "call_status": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "queued",
                  "dialing",
                  "ringing",
                  "in_progress",
                  "completed",
                  "failed",
                  "busy",
                  "no_answer",
                  "canceled"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Call Status",
            "description": "Current status of the call named by the id filter (e.g. id=call:<uuid>). Null for org-wide tails and non-call filters, since there is no single call to report a status for."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "EventStreamResponse"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail",
            "description": "List of validation errors: each entry gives the field location (loc), the problem (msg), and the error type (type)."
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "LLMConfig": {
        "properties": {
          "base_url": {
            "type": "string",
            "title": "Base Url",
            "description": "Public HTTPS base URL of the BYO LLM endpoint the call runs on. Must resolve to a public address — private/internal hosts are rejected."
          },
          "api_key": {
            "type": "string",
            "title": "Api Key",
            "description": "API key sent to the BYO LLM endpoint. Write-only — never echoed back."
          },
          "model": {
            "type": "string",
            "title": "Model",
            "description": "Model name to request from the BYO LLM endpoint."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "base_url",
          "api_key",
          "model"
        ],
        "title": "LLMConfig"
      },
      "MemberPhonePut": {
        "properties": {
          "phone_e164": {
            "type": "string",
            "title": "Phone E164",
            "description": "Phone number to save for the caller, E.164 format."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "phone_e164"
        ],
        "title": "MemberPhonePut"
      },
      "NumberAcquireRequest": {
        "properties": {
          "country_code": {
            "type": "string",
            "maxLength": 2,
            "minLength": 2,
            "title": "Country Code",
            "description": "ISO alpha-2 country code to acquire a number in (e.g. 'US'). Case-insensitive."
          },
          "number_type": {
            "type": "string",
            "enum": [
              "local",
              "mobile",
              "toll_free",
              "national"
            ],
            "title": "Number Type",
            "description": "Kind of number to acquire: 'local', 'mobile', 'toll_free', or 'national'.",
            "default": "local"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "country_code"
        ],
        "title": "NumberAcquireRequest"
      },
      "PhoneNumberListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/PhoneNumberResponse"
            },
            "type": "array",
            "title": "Items",
            "description": "Numbers in this page."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "PhoneNumberListResponse"
      },
      "PhoneNumberResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this number."
          },
          "e164": {
            "type": "string",
            "title": "E164",
            "description": "The phone number, E.164 format."
          },
          "country_code": {
            "type": "string",
            "title": "Country Code",
            "description": "ISO alpha-2 country code this number belongs to."
          },
          "number_type": {
            "type": "string",
            "title": "Number Type",
            "description": "Kind of number: 'local', 'mobile', 'toll_free', or 'national'."
          },
          "capabilities": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Capabilities",
            "description": "Channels this number supports, e.g. ['voice'], ['sms'], or both."
          },
          "provisioning_state": {
            "type": "string",
            "title": "Provisioning State",
            "description": "'pending', 'active', 'failed', or 'released'."
          },
          "is_dedicated": {
            "type": "boolean",
            "title": "Is Dedicated",
            "description": "True if this number is owned by the organization. False for shared-pool numbers."
          },
          "messaging_service_sid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Messaging Service Sid",
            "description": "Provider messaging-service identifier once SMS has been enabled on this number. Null until then."
          }
        },
        "type": "object",
        "required": [
          "id",
          "e164",
          "country_code",
          "number_type",
          "capabilities",
          "provisioning_state",
          "is_dedicated"
        ],
        "title": "PhoneNumberResponse"
      },
      "ProviderActivateRequest": {
        "properties": {
          "provider": {
            "type": "string",
            "title": "Provider",
            "description": "Previously saved provider to make active for this layer."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "provider"
        ],
        "title": "ProviderActivateRequest",
        "description": "Body of ``POST /providers/{layer}/activate``."
      },
      "ProviderConfigEntry": {
        "properties": {
          "layer": {
            "type": "string",
            "enum": [
              "llm",
              "tts",
              "stt"
            ],
            "title": "Layer",
            "description": "Voice-pipeline layer this config applies to."
          },
          "provider": {
            "type": "string",
            "title": "Provider",
            "description": "Provider name (e.g. 'openai', 'cartesia')."
          },
          "key_last4": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Key Last4",
            "description": "Last 4 characters of the saved API key, for display. Null if no key is saved."
          },
          "key_set_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Key Set At",
            "description": "When the API key was last set, ISO 8601 timestamp. Null if no key is saved."
          },
          "params": {
            "additionalProperties": true,
            "type": "object",
            "title": "Params",
            "description": "Saved provider-specific config for this row."
          },
          "fallback_enabled": {
            "type": "boolean",
            "title": "Fallback Enabled",
            "description": "Whether Hail's default provider is used as a fallback if this one fails."
          },
          "is_active": {
            "type": "boolean",
            "title": "Is Active",
            "description": "True if this is the row currently used by calls on this layer."
          }
        },
        "type": "object",
        "required": [
          "layer",
          "provider",
          "key_last4",
          "key_set_at",
          "params",
          "fallback_enabled",
          "is_active"
        ],
        "title": "ProviderConfigEntry",
        "description": "One saved provider row. Write-only key: ``key_last4`` and\n``key_set_at`` are the only key-derived fields that leave the API.\n\nEvery field is required (``key_last4``/``key_set_at`` nullable): the\nserializer always emits all of them, and required response fields\ngenerate plain values instead of pointers in the Go CLI's client."
      },
      "ProviderConfigListResponse": {
        "properties": {
          "providers": {
            "items": {
              "$ref": "#/components/schemas/ProviderConfigEntry"
            },
            "type": "array",
            "title": "Providers",
            "description": "Every saved provider row for the organization, across all layers."
          }
        },
        "type": "object",
        "required": [
          "providers"
        ],
        "title": "ProviderConfigListResponse"
      },
      "ProviderConfigUpsert": {
        "properties": {
          "provider": {
            "type": "string",
            "title": "Provider",
            "description": "Provider name to save/activate for this layer (e.g. 'openai', 'cartesia')."
          },
          "api_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Api Key",
            "description": "API key for this provider. Omit to edit params without resending the key. Write-only — never echoed back."
          },
          "params": {
            "additionalProperties": true,
            "type": "object",
            "title": "Params",
            "description": "Provider-specific config, validated against the layer's schema (LLMParams/TTSParams/STTParams). Only the keys you send are changed; other saved keys are kept."
          },
          "fallback_enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fallback Enabled",
            "description": "Whether to fall back to Hail's default provider on failure. Omit to leave unchanged; defaults to false on a new row."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "provider"
        ],
        "title": "ProviderConfigUpsert",
        "description": "Body of ``PUT /providers/{layer}`` — save and activate one provider.\n\nA partial write. Fields you omit keep the value already saved for this\n``(layer, provider)`` pair: omit ``api_key`` to edit params without\nresending the key, send only the ``params`` keys you want to change,\nand omit ``fallback_enabled`` to leave the flag as it is. The merged\nresult is what gets validated against the layer's schema (422 on a\nmismatch), so a partial write can never leave an invalid config behind.\n\nRows are keyed by ``(organization, layer, provider)``, so writing a\n*different* provider for the same layer starts from scratch rather than\ninheriting the previous provider's params. On a brand-new row\n``fallback_enabled`` defaults to ``false``.\n\nKeys are write-only: no response ever echoes one back."
      },
      "ProviderValidateRequest": {
        "properties": {
          "api_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Api Key",
            "description": "Key to test instead of the stored one. Not persisted."
          },
          "provider": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider",
            "description": "Provider to test. Omitted: the layer's currently active provider."
          },
          "params": {
            "additionalProperties": true,
            "type": "object",
            "title": "Params",
            "description": "Provider-specific config to test alongside the key."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "ProviderValidateRequest",
        "description": "Body of ``POST /providers/{layer}/validate`` — a live key probe.\n\nAll fields optional: with an empty body the layer's active provider and\nits stored key are tested. ``provider`` tests that provider's stored key\ninstead. ``api_key`` tests a key that has not been saved yet."
      },
      "ProviderValidateResult": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Probe outcome: 'valid', 'invalid', or 'indeterminate' (the provider could not be reached)."
          },
          "message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message",
            "description": "Human-readable detail about the outcome. 'ok' on success, an error description otherwise."
          }
        },
        "type": "object",
        "required": [
          "status",
          "message"
        ],
        "title": "ProviderValidateResult",
        "description": "Outcome of a live provider-key probe."
      },
      "SenderIdPatch": {
        "properties": {
          "custom_sender_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom Sender Id",
            "description": "Alphanumeric sender id (2-11 characters, letters/digits only) to use on alphanumeric-eligible corridors instead of a phone number. Explicit null clears it, reverting to the platform default."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "SenderIdPatch"
      },
      "SenderIdResponse": {
        "properties": {
          "custom_sender_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom Sender Id",
            "description": "The organization's configured alphanumeric sender id. Null if none is set."
          },
          "effective_default": {
            "type": "string",
            "title": "Effective Default",
            "description": "The platform's alphanumeric sender id, used on eligible corridors when custom_sender_id is null.",
            "default": "HAIL"
          }
        },
        "type": "object",
        "required": [
          "custom_sender_id"
        ],
        "title": "SenderIdResponse"
      },
      "SmsCreate": {
        "properties": {
          "recipient_consent": {
            "type": "boolean",
            "title": "Recipient Consent",
            "description": "Attestation that you have obtained the lawful consent required to contact this recipient. Hail does not verify consent itself — you are responsible for a lawful basis under TCPA/ePrivacy/PECR/CAN-SPAM/GDPR as applicable. Rejected (422) if not true."
          },
          "consent_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consent Source",
            "description": "Where/how consent was obtained (e.g. 'signup form', 'prior customer relationship'). Required (non-empty) when message_type is 'marketing'."
          },
          "consent_obtained_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consent Obtained At",
            "description": "When consent was obtained, if known."
          },
          "message_type": {
            "type": "string",
            "enum": [
              "marketing",
              "informational"
            ],
            "title": "Message Type",
            "description": "'marketing' additionally requires a non-empty consent_source. Use 'informational' for transactional/service communications.",
            "default": "informational"
          },
          "to": {
            "type": "string",
            "title": "To",
            "description": "Recipient phone number, E.164 format (e.g. +14155551234)."
          },
          "from": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "From",
            "description": "Sender phone number, E.164 format. Must be a number owned by the organization with the SMS capability. Omitted: an active org-owned number is used if one exists, else a number is claimed from the shared pool."
          },
          "body": {
            "type": "string",
            "maxLength": 1600,
            "minLength": 1,
            "title": "Body",
            "description": "Message text. Long bodies are split into multiple carrier segments."
          },
          "metadata": {
            "additionalProperties": true,
            "type": "object",
            "title": "Metadata",
            "description": "Free-form JSON object attached to the message and echoed back on reads. Not interpreted by Hail."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "recipient_consent",
          "to",
          "body"
        ],
        "title": "SmsCreate"
      },
      "SmsListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/SmsResponse"
            },
            "type": "array",
            "title": "Items",
            "description": "Messages in this page, newest first."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "SmsListResponse"
      },
      "SmsResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this message."
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "title": "Organization Id",
            "description": "Organization that sent or received this message."
          },
          "from_e164": {
            "type": "string",
            "title": "From E164",
            "description": "Sender phone number, E.164 format."
          },
          "to_e164": {
            "type": "string",
            "title": "To E164",
            "description": "Recipient phone number, E.164 format."
          },
          "direction": {
            "type": "string",
            "enum": [
              "outbound",
              "inbound"
            ],
            "title": "Direction",
            "description": "'outbound' for messages Hail sent, 'inbound' for messages received."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "sent",
              "delivered",
              "failed",
              "undelivered",
              "received"
            ],
            "title": "Status",
            "description": "Delivery status: 'queued', 'sent', 'delivered', 'failed', 'undelivered', or 'received' (inbound messages)."
          },
          "body": {
            "type": "string",
            "title": "Body",
            "description": "Message text."
          },
          "provider_message_sid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider Message Sid",
            "description": "The carrier/provider's identifier for this message, if assigned."
          },
          "segment_count": {
            "type": "integer",
            "title": "Segment Count",
            "description": "Number of carrier SMS segments the body was split into."
          },
          "error_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error Code",
            "description": "Carrier error code if delivery failed. Null on success or while pending."
          },
          "requested_at": {
            "type": "string",
            "format": "date-time",
            "title": "Requested At",
            "description": "When the send was requested, ISO 8601 timestamp."
          },
          "sent_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sent At",
            "description": "When the message was handed to the carrier, ISO 8601 timestamp. Null until sent."
          }
        },
        "type": "object",
        "required": [
          "id",
          "organization_id",
          "from_e164",
          "to_e164",
          "direction",
          "status",
          "body",
          "provider_message_sid",
          "segment_count",
          "error_code",
          "requested_at",
          "sent_at"
        ],
        "title": "SmsResponse"
      },
      "SuppressionListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/SuppressionResponse"
            },
            "type": "array",
            "title": "Items",
            "description": "Suppressed recipients in this page."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "SuppressionListResponse"
      },
      "SuppressionResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this suppression entry."
          },
          "recipient": {
            "type": "string",
            "title": "Recipient",
            "description": "The suppressed recipient — E.164 phone number for voice/sms, lowercased email address for email."
          },
          "channel": {
            "type": "string",
            "title": "Channel",
            "description": "Channel this entry blocks sends on: 'voice', 'email', 'sms', or 'all' (every channel)."
          },
          "reason": {
            "type": "string",
            "title": "Reason",
            "description": "Why the recipient was suppressed (e.g. an unsubscribe or a bounce)."
          },
          "source": {
            "type": "string",
            "title": "Source",
            "description": "How this entry was created: 'unsubscribe_link', 'manual' (an operator action), or 'bounce'."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "When this entry was created, ISO 8601 timestamp."
          }
        },
        "type": "object",
        "required": [
          "id",
          "recipient",
          "channel",
          "reason",
          "source",
          "created_at"
        ],
        "title": "SuppressionResponse"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location",
            "description": "Path to the invalid field within the request, as a list of keys/indices (e.g. ['body', 'to'])."
          },
          "msg": {
            "type": "string",
            "title": "Message",
            "description": "Human-readable description of the validation failure."
          },
          "type": {
            "type": "string",
            "title": "Error Type",
            "description": "Machine-readable error type code (e.g. 'missing', 'string_type')."
          },
          "input": {
            "title": "Input",
            "description": "The value that was actually provided and failed validation."
          },
          "ctx": {
            "type": "object",
            "title": "Context",
            "description": "Additional machine-readable context for the error, when the error type provides one."
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "VoiceConfig": {
        "properties": {
          "tts": {
            "type": "string",
            "const": "cartesia",
            "title": "Tts",
            "description": "Text-to-speech provider. Currently only 'cartesia'.",
            "default": "cartesia"
          },
          "vad": {
            "type": "string",
            "const": "silero",
            "title": "Vad",
            "description": "Voice-activity-detection engine. Currently only 'silero'.",
            "default": "silero"
          },
          "turn_detection": {
            "type": "string",
            "const": "livekit",
            "title": "Turn Detection",
            "description": "Turn-detection engine. Currently only 'livekit'.",
            "default": "livekit"
          },
          "voice_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Voice Id",
            "description": "Per-call TTS voice override, applied to whichever TTS provider serves the call. Omitted: the organization's or environment's default voice."
          },
          "language": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "ar",
                  "bg",
                  "bn",
                  "cs",
                  "da",
                  "de",
                  "el",
                  "en",
                  "es",
                  "fi",
                  "fr",
                  "gu",
                  "he",
                  "hi",
                  "hr",
                  "hu",
                  "id",
                  "it",
                  "ja",
                  "kn",
                  "ko",
                  "mr",
                  "ms",
                  "nl",
                  "no",
                  "pl",
                  "pt",
                  "ro",
                  "ru",
                  "sk",
                  "sv",
                  "ta",
                  "te",
                  "th",
                  "tl",
                  "tr",
                  "uk",
                  "vi",
                  "zh"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Language",
            "description": "Spoken language for the call as a lowercase ISO 639-1 code (e.g. 'da'). One of the 39 supported codes — see docs/languages.md. Applied to STT, TTS, and turn detection. Omitted: the providers' defaults (English)."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "VoiceConfig"
      },
      "WebhookDeliveryListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/WebhookDeliveryResponse"
            },
            "type": "array",
            "title": "Items",
            "description": "Delivery attempts in this page."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "WebhookDeliveryListResponse"
      },
      "WebhookDeliveryResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this delivery attempt."
          },
          "subscription_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Subscription Id",
            "description": "Subscription this delivery belongs to."
          },
          "email_domain_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email Domain Id",
            "description": "Email domain the triggering event relates to, if any. Informational only (surfaced as the X-Hail-Email-Domain header) — not a routing target."
          },
          "event_type": {
            "type": "string",
            "title": "Event Type",
            "description": "The event type being delivered (e.g. 'call.completed')."
          },
          "event_id": {
            "type": "string",
            "format": "uuid",
            "title": "Event Id",
            "description": "Identifier of the underlying event that triggered this delivery."
          },
          "attempt": {
            "type": "integer",
            "title": "Attempt",
            "description": "Number of delivery attempts made so far for this event, starting at 0."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "succeeded",
              "failed",
              "dead"
            ],
            "title": "Status",
            "description": "'pending' (queued/retrying), 'succeeded', 'failed' (will retry), or 'dead' (retries exhausted)."
          },
          "response_status": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Response Status",
            "description": "HTTP status code returned by the target URL on the last attempt. Null before any attempt."
          },
          "response_body": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Response Body",
            "description": "Response body returned by the target URL on the last attempt, if any. Null before any attempt."
          },
          "next_attempt_at": {
            "type": "string",
            "format": "date-time",
            "title": "Next Attempt At",
            "description": "When the next delivery attempt is scheduled, ISO 8601 timestamp."
          },
          "succeeded_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Succeeded At",
            "description": "When this delivery succeeded, ISO 8601 timestamp. Null until it does."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "When this delivery was queued, ISO 8601 timestamp."
          }
        },
        "type": "object",
        "required": [
          "id",
          "subscription_id",
          "email_domain_id",
          "event_type",
          "event_id",
          "attempt",
          "status",
          "next_attempt_at",
          "created_at"
        ],
        "title": "WebhookDeliveryResponse"
      },
      "WebhookSubscriptionCreate": {
        "properties": {
          "target_url": {
            "type": "string",
            "minLength": 1,
            "title": "Target Url",
            "description": "HTTPS URL Hail POSTs event payloads to."
          },
          "event_types": {
            "items": {
              "type": "string",
              "enum": [
                "email.received",
                "email.delivered",
                "email.delivery_delayed",
                "email.bounced",
                "email.complained",
                "email.opened",
                "email.clicked",
                "email.received.suppressed",
                "email.send_failed",
                "sms.received",
                "sms.delivered",
                "sms.undelivered",
                "sms.failed",
                "call.answered",
                "call.completed",
                "call.failed",
                "call.busy",
                "call.no_answer"
              ]
            },
            "type": "array",
            "minItems": 1,
            "title": "Event Types",
            "description": "Event types to subscribe to (e.g. 'call.completed', 'email.bounced'). At least one required."
          }
        },
        "type": "object",
        "required": [
          "target_url",
          "event_types"
        ],
        "title": "WebhookSubscriptionCreate"
      },
      "WebhookSubscriptionListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/WebhookSubscriptionResponse"
            },
            "type": "array",
            "title": "Items",
            "description": "Subscriptions in this page."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor",
            "description": "Opaque cursor for the next page. Null when there are no more results."
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "WebhookSubscriptionListResponse"
      },
      "WebhookSubscriptionPatch": {
        "properties": {
          "target_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Target Url",
            "description": "New delivery URL. Omit to leave unchanged."
          },
          "event_types": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "enum": [
                    "email.received",
                    "email.delivered",
                    "email.delivery_delayed",
                    "email.bounced",
                    "email.complained",
                    "email.opened",
                    "email.clicked",
                    "email.received.suppressed",
                    "email.send_failed",
                    "sms.received",
                    "sms.delivered",
                    "sms.undelivered",
                    "sms.failed",
                    "call.answered",
                    "call.completed",
                    "call.failed",
                    "call.busy",
                    "call.no_answer"
                  ]
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Event Types",
            "description": "New set of subscribed event types. Omit to leave unchanged."
          },
          "status": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "active",
                  "disabled"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Status",
            "description": "Set to 'disabled' to pause deliveries, or 'active' to resume. Omit to leave unchanged."
          }
        },
        "type": "object",
        "title": "WebhookSubscriptionPatch"
      },
      "WebhookSubscriptionResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id",
            "description": "Unique identifier for this subscription."
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "title": "Organization Id",
            "description": "Organization that owns this subscription."
          },
          "target_url": {
            "type": "string",
            "title": "Target Url",
            "description": "HTTPS URL event payloads are POSTed to."
          },
          "event_types": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Event Types",
            "description": "Event types this subscription receives."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "disabled"
            ],
            "title": "Status",
            "description": "'active' (delivering) or 'disabled' (paused)."
          },
          "consecutive_failures": {
            "type": "integer",
            "title": "Consecutive Failures",
            "description": "Consecutive failed delivery attempts since the last success. Resets to 0 on success."
          },
          "last_success_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Success At",
            "description": "When a delivery last succeeded, ISO 8601 timestamp. Null if never."
          },
          "last_failure_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Failure At",
            "description": "When a delivery last failed, ISO 8601 timestamp. Null if never."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "When this subscription was created, ISO 8601 timestamp."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "title": "Updated At",
            "description": "When this subscription was last modified, ISO 8601 timestamp."
          },
          "secret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Secret",
            "description": "Plaintext signing secret for verifying delivery payloads. Only present in the create and rotate-secret responses; every later read returns null."
          }
        },
        "type": "object",
        "required": [
          "id",
          "organization_id",
          "target_url",
          "event_types",
          "status",
          "consecutive_failures",
          "created_at",
          "updated_at"
        ],
        "title": "WebhookSubscriptionResponse",
        "description": "Subscription as returned by the API.\n\n``secret`` is populated **only** by create + rotate-secret responses;\nlater GETs return ``None`` so the plaintext never round-trips."
      },
      "WhoamiResponse": {
        "properties": {
          "auth_kind": {
            "type": "string",
            "enum": [
              "apikey",
              "jwt",
              "shared"
            ],
            "title": "Auth Kind",
            "description": "How the caller authenticated: 'apikey' (org API key), 'jwt' (logged-in user session), or 'shared' (the shared HAIL_API_KEY, which carries no human identity)."
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "title": "Organization Id",
            "description": "Organization the caller belongs to."
          },
          "user_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "User Id",
            "description": "The authenticated user's id. Null for 'shared' callers."
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "The authenticated user's email. Null for 'shared' callers."
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "The authenticated user's display name. Null for 'shared' callers."
          }
        },
        "type": "object",
        "required": [
          "auth_kind",
          "organization_id"
        ],
        "title": "WhoamiResponse",
        "description": "Who the caller is — the answer ``GET /whoami`` gives.\n\n``user_id``/``email``/``name`` are ``None`` for shared-key\n(``HAIL_API_KEY``) callers: that key carries no human identity. An\nagent that wants to put the operator's address in ``Reply-To`` reads\n``email`` and skips the header when it is ``None``."
      }
    }
  }
}
