{
  "openapi": "3.1.0",
  "info": {
    "title": "Yanola Developer Platform WhatsApp API",
    "version": "1.0.0-beta.0",
    "description": "Development v1 contract with first-class phone and typed WhatsApp identity support. Regular BSUID sending remains account- and Sender-gated; parent BSUID sending remains disabled until separately verified.",
    "x-yanola-stability": "beta",
    "x-yanola-breaking-changes": "new-major-base-path"
  },
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "servers": [
    {
      "url": "https://api.yanola.ai/v1",
      "description": "Yanola API v1"
    }
  ],
  "security": [
    {
      "YanolaApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Messages",
      "description": "Send and read WhatsApp messages through Yanola."
    },
    {
      "name": "Senders",
      "description": "Read connected WhatsApp Senders available to the Agent Project."
    },
    {
      "name": "Templates",
      "description": "Read approved WhatsApp templates cached for a Sender."
    },
    {
      "name": "Media",
      "description": "Retrieve inbound media without Meta credentials."
    },
    {
      "name": "Events",
      "description": "Read Developer Platform events."
    },
    {
      "name": "Webhook deliveries",
      "description": "Read and replay Developer Platform webhook deliveries."
    },
    {
      "name": "Usage",
      "description": "Read Yanola Balance usage records for public API activity."
    }
  ],
  "paths": {
    "/messages/text": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "sendTextMessage",
        "summary": "Send a text message",
        "description": "Queues a text message. Live Mode sends through Meta and consumes Yanola Balance after provider chargeability is known. Test Mode validates against a real connected Sender, then records a completed synthetic message, zero-cost usage, and a sent event without calling Meta or consuming balance. Text sends to a typed BSUID require live account and Sender capability. Non-template text also requires an active Customer Service Window. Yanola never switches to a known phone implicitly. Use either the unchanged legacy 'to' field or one typed 'recipient', never both. The authenticated API key, Agent Project, and verified 'from' Sender determine tenant and Business Portfolio scope; a caller-supplied scope field is invalid. Regular BSUID sending is account/Sender gated. Parent BSUID sending remains disabled until separately verified. Capability or scope failures never trigger automatic phone fallback. Meta error 131062 is exposed asynchronously as stable failure code 'whatsapp_unsupported_recipient' without retrying the same route unchanged.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/TextMessageSend"
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/MessageAccepted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientBalance"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/BusinessStateInvalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-yanola-recipient-kinds": [
          "phone",
          "regular_bsuid",
          "parent_bsuid"
        ],
        "x-yanola-parent-bsuid-capability": "disabled-until-verified"
      }
    },
    "/messages/template": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "sendTemplateMessage",
        "summary": "Send an approved template message",
        "description": "Queues an approved WhatsApp template message. Template sends can start conversations outside the Customer Service Window when the template and components validate for the Sender. Test Mode validates the approved cached template and records synthetic message, usage, and event logs without calling Meta or consuming balance. BSUID routes are limited to templates with trusted utility or marketing capability. One-tap, zero-tap, copy-code, authentication, and unclassified templates are phone-only and fail without route fallback. Use either the unchanged legacy 'to' field or one typed 'recipient', never both. The authenticated API key, Agent Project, and verified 'from' Sender determine tenant and Business Portfolio scope; a caller-supplied scope field is invalid. Regular BSUID sending is account/Sender gated. Parent BSUID sending remains disabled until separately verified. Capability or scope failures never trigger automatic phone fallback. Meta error 131062 is exposed asynchronously as stable failure code 'whatsapp_unsupported_recipient' without retrying the same route unchanged.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/TemplateMessageSend"
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/MessageAccepted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientBalance"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/BusinessStateInvalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-yanola-recipient-kinds": [
          "phone",
          "regular_bsuid",
          "parent_bsuid"
        ],
        "x-yanola-parent-bsuid-capability": "disabled-until-verified"
      }
    },
    "/messages/media": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "sendMediaMessage",
        "summary": "Send a media message by URL",
        "description": "Queues an image, video, document, or audio message using a developer-provided public URL. Public media upload is not part of v1. Test Mode records synthetic message, usage, and event logs without fetching the media, calling Meta, or consuming balance. Image, video, document, and audio BSUID sends require live account and Sender capability plus an active Customer Service Window. Audio captions and filenames on non-document media remain invalid. Use either the unchanged legacy 'to' field or one typed 'recipient', never both. The authenticated API key, Agent Project, and verified 'from' Sender determine tenant and Business Portfolio scope; a caller-supplied scope field is invalid. Regular BSUID sending is account/Sender gated. Parent BSUID sending remains disabled until separately verified. Capability or scope failures never trigger automatic phone fallback. Meta error 131062 is exposed asynchronously as stable failure code 'whatsapp_unsupported_recipient' without retrying the same route unchanged.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/MediaMessageSend"
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/MessageAccepted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientBalance"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/BusinessStateInvalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-yanola-recipient-kinds": [
          "phone",
          "regular_bsuid",
          "parent_bsuid"
        ],
        "x-yanola-parent-bsuid-capability": "disabled-until-verified"
      }
    },
    "/messages/location": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "sendLocationMessage",
        "summary": "Send a location message",
        "description": "Queues a location message. Test Mode validates the payload and real connected Sender, then records synthetic message, usage, and event logs without calling Meta or consuming balance. Location BSUID sends require live account and Sender capability plus an active Customer Service Window. Use either the unchanged legacy 'to' field or one typed 'recipient', never both. The authenticated API key, Agent Project, and verified 'from' Sender determine tenant and Business Portfolio scope; a caller-supplied scope field is invalid. Regular BSUID sending is account/Sender gated. Parent BSUID sending remains disabled until separately verified. Capability or scope failures never trigger automatic phone fallback. Meta error 131062 is exposed asynchronously as stable failure code 'whatsapp_unsupported_recipient' without retrying the same route unchanged.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/LocationMessageSend"
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/MessageAccepted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientBalance"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/BusinessStateInvalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-yanola-recipient-kinds": [
          "phone",
          "regular_bsuid",
          "parent_bsuid"
        ],
        "x-yanola-parent-bsuid-capability": "disabled-until-verified"
      }
    },
    "/messages/contact-card": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "sendContactCardMessage",
        "summary": "Send a contact-card message",
        "description": "Queues a WhatsApp Contact Card Message. This does not create or mutate saved contact records. Test Mode records synthetic message, usage, and event logs without calling Meta or consuming balance. Contact-card BSUID sends require live account and Sender capability plus an active Customer Service Window. Sending a card does not create or mutate a saved contact. Use either the unchanged legacy 'to' field or one typed 'recipient', never both. The authenticated API key, Agent Project, and verified 'from' Sender determine tenant and Business Portfolio scope; a caller-supplied scope field is invalid. Regular BSUID sending is account/Sender gated. Parent BSUID sending remains disabled until separately verified. Capability or scope failures never trigger automatic phone fallback. Meta error 131062 is exposed asynchronously as stable failure code 'whatsapp_unsupported_recipient' without retrying the same route unchanged.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/ContactCardMessageSend"
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/MessageAccepted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientBalance"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/BusinessStateInvalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-yanola-recipient-kinds": [
          "phone",
          "regular_bsuid",
          "parent_bsuid"
        ],
        "x-yanola-parent-bsuid-capability": "disabled-until-verified"
      }
    },
    "/messages/{messageId}/mark-read": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "markMessageAsRead",
        "summary": "Mark an inbound message as read",
        "description": "Marks a Yanola inbound message ID as read. Raw Meta message IDs are not accepted.",
        "parameters": [
          {
            "$ref": "#/components/parameters/MessageIdPath"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/MessageMarkedRead"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/BusinessStateInvalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/messages": {
      "get": {
        "tags": [
          "Messages"
        ],
        "operationId": "listMessages",
        "summary": "List public message logs",
        "parameters": [
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Environment"
          },
          {
            "$ref": "#/components/parameters/Direction"
          },
          {
            "$ref": "#/components/parameters/From"
          },
          {
            "$ref": "#/components/parameters/To"
          },
          {
            "$ref": "#/components/parameters/MessageStatus"
          },
          {
            "$ref": "#/components/parameters/MessageType"
          },
          {
            "$ref": "#/components/parameters/CreatedAfter"
          },
          {
            "$ref": "#/components/parameters/CreatedBefore"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/MessageList"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/messages/{messageId}": {
      "get": {
        "tags": [
          "Messages"
        ],
        "operationId": "retrieveMessage",
        "summary": "Retrieve a public message log entry",
        "parameters": [
          {
            "$ref": "#/components/parameters/MessageIdPath"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/MessageRetrieved"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/senders": {
      "get": {
        "tags": [
          "Senders"
        ],
        "operationId": "listSenders",
        "summary": "List Senders",
        "parameters": [
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Environment"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/SenderList"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/templates": {
      "get": {
        "tags": [
          "Templates"
        ],
        "operationId": "listTemplates",
        "summary": "List approved templates for a Sender",
        "parameters": [
          {
            "$ref": "#/components/parameters/FromRequired"
          },
          {
            "$ref": "#/components/parameters/RefreshTemplates"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Environment"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/TemplateList"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/BusinessStateInvalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/media/{mediaId}": {
      "get": {
        "tags": [
          "Media"
        ],
        "operationId": "retrieveMedia",
        "summary": "Retrieve inbound media metadata and download URL",
        "description": "Requires messages:read. The media ID is Yanola-issued; raw Meta media IDs are not accepted. Access is restricted to the API key's Yanola Account, Agent Project, environment, and permitted Senders. downloadUrl is a short-lived signed Yanola proxy URL and does not expose Meta credentials or Yanola's permanent cache location.",
        "parameters": [
          {
            "$ref": "#/components/parameters/MediaIdPath"
          },
          {
            "$ref": "#/components/parameters/Environment"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/MediaRetrieved"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "operationId": "listEvents",
        "summary": "List Developer Platform events",
        "description": "Requires `events:read`. Returns only events in the Yanola Account, Agent Project, API key environment, and optional API-key Sender restriction. Event `data` is the retained Yanola-normalized projection; raw Meta/provider payloads and internal raw-payload references are never returned by this endpoint.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Environment"
          },
          {
            "$ref": "#/components/parameters/EventType"
          },
          {
            "$ref": "#/components/parameters/From"
          },
          {
            "$ref": "#/components/parameters/CreatedAfter"
          },
          {
            "$ref": "#/components/parameters/CreatedBefore"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/EventList"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/events/{eventId}": {
      "get": {
        "tags": [
          "Events"
        ],
        "operationId": "retrieveEvent",
        "summary": "Retrieve a Developer Platform event",
        "description": "Requires `events:read`. Missing, malformed, cross-environment, cross-project, and Sender-restricted event IDs share the same not-found response. The response contains normalized event data only and never exposes raw Meta/provider payloads or their internal storage references.",
        "parameters": [
          {
            "$ref": "#/components/parameters/EventIdPath"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/EventRetrieved"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/webhook-deliveries": {
      "get": {
        "tags": [
          "Webhook deliveries"
        ],
        "operationId": "listWebhookDeliveries",
        "summary": "List webhook deliveries",
        "description": "Requires webhooks:read. Returns only delivery summaries in the API key's Yanola Account, Agent Project, environment, and allowed Sender set. Endpoint identifiers, request payloads, secrets, and unredacted responses are never returned.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Environment"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryStatus"
          },
          {
            "$ref": "#/components/parameters/EventIdQuery"
          },
          {
            "$ref": "#/components/parameters/CreatedAfter"
          },
          {
            "$ref": "#/components/parameters/CreatedBefore"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookDeliveryList"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/webhook-deliveries/{deliveryId}": {
      "get": {
        "tags": [
          "Webhook deliveries"
        ],
        "operationId": "retrieveWebhookDelivery",
        "summary": "Retrieve a webhook delivery",
        "description": "Requires webhooks:read. Malformed, missing, cross-environment, and inaccessible delivery IDs return the same not-found response.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DeliveryIdPath"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookDeliveryRetrieved"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/webhook-deliveries/{deliveryId}/replay": {
      "post": {
        "tags": [
          "Webhook deliveries"
        ],
        "operationId": "replayWebhookDelivery",
        "summary": "Replay a webhook delivery",
        "description": "Requires webhooks:write. Creates a new pending delivery ID for the same event and endpoint when the source delivery failed. The replay is delivered with yanola-replayed: true.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DeliveryIdPath"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "202": {
            "$ref": "#/components/responses/WebhookDeliveryReplayAccepted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/BusinessStateInvalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/usage": {
      "get": {
        "tags": [
          "Usage"
        ],
        "operationId": "listUsage",
        "summary": "List Developer Platform usage records",
        "description": "Requires usage:read. Records are restricted to the API key's Yanola Account, Agent Project, environment, and permitted Senders. Pricing breakdown fields use the latest immutable estimate, provider-status, or reconciliation snapshot. totalAmount is the finalized Yanola Balance charge and remains zero for reserved, released, or reconciliation-needed usage.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Environment"
          },
          {
            "$ref": "#/components/parameters/From"
          },
          {
            "$ref": "#/components/parameters/UsageStatus"
          },
          {
            "$ref": "#/components/parameters/UsageCategory"
          },
          {
            "$ref": "#/components/parameters/CreatedAfter"
          },
          {
            "$ref": "#/components/parameters/CreatedBefore"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/UsageList"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    }
  },
  "webhooks": {
    "yanolaEvent": {
      "post": {
        "operationId": "receiveYanolaWebhook",
        "summary": "Receive a signed Yanola Developer Event",
        "description": "Yanola sends at-least-once HTTPS POST deliveries for endpoints explicitly configured with contract_version v1. Verify yanola-signature against the exact raw body before parsing, deduplicate durable effects by the stable yanola-event-id, and return any 2xx response after durable acceptance. The signing secret, signature input, retry schedule, event ID, and replay rules are unchanged from v1; yanola-contract-version selects only the identity schema.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/YanolaSignature"
          },
          {
            "$ref": "#/components/parameters/YanolaTimestamp"
          },
          {
            "$ref": "#/components/parameters/YanolaEventId"
          },
          {
            "$ref": "#/components/parameters/YanolaDeliveryId"
          },
          {
            "$ref": "#/components/parameters/YanolaPayloadFormat"
          },
          {
            "$ref": "#/components/parameters/YanolaReplayed"
          },
          {
            "$ref": "#/components/parameters/YanolaContractVersion"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/YanolaWebhookPayload"
                  },
                  {
                    "$ref": "#/components/schemas/MetaWebhookPayload"
                  },
                  {
                    "$ref": "#/components/schemas/YanolaWebhookPayloadWithRaw"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "The consumer durably accepted the delivery. Any 2xx response is treated as success."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "YanolaApiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "yalo_live_<apk_id>_<secret> or yalo_test_<apk_id>_<secret>",
        "description": "Send the Yanola API Key in the Authorization header as Bearer credentials."
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Unique key for safe retries. Mutation endpoints scope it by Agent Project, environment, concrete endpoint, API key, and request body hash.",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 255
        },
        "example": "send-order-123"
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "Opaque cursor returned by the previous list response.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 1024
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 20
        }
      },
      "Environment": {
        "name": "environment",
        "in": "query",
        "required": false,
        "description": "Filter by Developer Platform environment. Defaults to the API key environment when omitted.",
        "schema": {
          "$ref": "#/components/schemas/Environment"
        }
      },
      "Direction": {
        "name": "direction",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/MessageDirection"
        }
      },
      "From": {
        "name": "from",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/E164PhoneNumber"
        }
      },
      "FromRequired": {
        "name": "from",
        "in": "query",
        "required": true,
        "description": "Sender phone number in E.164 format.",
        "schema": {
          "$ref": "#/components/schemas/E164PhoneNumber"
        },
        "example": "+15557654321"
      },
      "To": {
        "name": "to",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/E164PhoneNumber"
        }
      },
      "MessageStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/MessageStatus"
        }
      },
      "MessageType": {
        "name": "type",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/MessageType"
        }
      },
      "CreatedAfter": {
        "name": "created_after",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "CreatedBefore": {
        "name": "created_before",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "RefreshTemplates": {
        "name": "refresh",
        "in": "query",
        "required": false,
        "schema": {
          "type": "boolean",
          "default": false
        }
      },
      "EventType": {
        "name": "type",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/EventType"
        }
      },
      "EventIdQuery": {
        "name": "eventId",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/EventId"
        }
      },
      "WebhookDeliveryStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/WebhookDeliveryStatus"
        }
      },
      "UsageStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/UsageStatus"
        }
      },
      "UsageCategory": {
        "name": "category",
        "in": "query",
        "required": false,
        "description": "Filter by the provider message category captured in the usage pricing record.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 80
        }
      },
      "MessageIdPath": {
        "name": "messageId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/PublicMessageId"
        }
      },
      "MediaIdPath": {
        "name": "mediaId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/MediaId"
        }
      },
      "EventIdPath": {
        "name": "eventId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/EventId"
        }
      },
      "DeliveryIdPath": {
        "name": "deliveryId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/WebhookDeliveryId"
        }
      },
      "YanolaSignature": {
        "name": "yanola-signature",
        "in": "header",
        "required": true,
        "description": "HMAC-SHA256 signature over <timestamp>.<exact raw body>. Can contain multiple v1 digests during signing-secret rotation.",
        "schema": {
          "type": "string",
          "minLength": 1
        }
      },
      "YanolaTimestamp": {
        "name": "yanola-timestamp",
        "in": "header",
        "required": true,
        "description": "Unix timestamp in seconds used by the webhook signature.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "YanolaEventId": {
        "name": "yanola-event-id",
        "in": "header",
        "required": true,
        "description": "Stable event identity for consumer deduplication.",
        "schema": {
          "$ref": "#/components/schemas/EventId"
        }
      },
      "YanolaDeliveryId": {
        "name": "yanola-delivery-id",
        "in": "header",
        "required": true,
        "description": "Identity of this delivery attempt for diagnostics.",
        "schema": {
          "$ref": "#/components/schemas/WebhookDeliveryId"
        }
      },
      "YanolaPayloadFormat": {
        "name": "yanola-payload-format",
        "in": "header",
        "required": true,
        "description": "Webhook body mode selected for the endpoint.",
        "schema": {
          "$ref": "#/components/schemas/WebhookPayloadFormat"
        }
      },
      "YanolaReplayed": {
        "name": "yanola-replayed",
        "in": "header",
        "required": false,
        "description": "Present with true only when the delivery was created by a manual replay.",
        "schema": {
          "type": "string",
          "const": "true"
        }
      },
      "YanolaContractVersion": {
        "name": "yanola-contract-version",
        "in": "header",
        "required": true,
        "description": "Identity contract version snapshotted when this delivery was created. Endpoint payload mode is negotiated independently.",
        "schema": {
          "type": "string",
          "const": "v1"
        }
      }
    },
    "headers": {
      "RequestId": {
        "description": "Yanola request ID for support and debugging.",
        "schema": {
          "type": "string",
          "pattern": "^req_[A-Za-z0-9_-]+$"
        }
      },
      "RateLimitLimit": {
        "description": "Maximum requests allowed in the current window.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "RateLimitRemaining": {
        "description": "Remaining requests in the current window.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "RateLimitReset": {
        "description": "Unix timestamp when the current rate-limit window resets.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying a rate-limited or temporarily unavailable request.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "requestBodies": {
      "TextMessageSend": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/TextMessageSendRequest"
            },
            "examples": {
              "legacyPhone": {
                "$ref": "#/components/examples/TextSendLegacyPhoneRequest"
              },
              "typedPhone": {
                "$ref": "#/components/examples/TextSendTypedPhoneRequest"
              },
              "regularBsuid": {
                "$ref": "#/components/examples/TextSendRegularBsuidRequest"
              },
              "parentBsuid": {
                "$ref": "#/components/examples/TextSendParentBsuidRequest"
              }
            }
          }
        }
      },
      "TemplateMessageSend": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/TemplateMessageSendRequest"
            },
            "examples": {
              "legacyPhone": {
                "$ref": "#/components/examples/TemplateSendLegacyPhoneRequest"
              },
              "regularBsuid": {
                "$ref": "#/components/examples/TemplateSendRegularBsuidRequest"
              }
            }
          }
        }
      },
      "MediaMessageSend": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MediaMessageSendRequest"
            },
            "examples": {
              "legacyPhone": {
                "$ref": "#/components/examples/MediaSendLegacyPhoneRequest"
              },
              "regularBsuid": {
                "$ref": "#/components/examples/MediaSendRegularBsuidRequest"
              }
            }
          }
        }
      },
      "LocationMessageSend": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/LocationMessageSendRequest"
            },
            "examples": {
              "legacyPhone": {
                "$ref": "#/components/examples/LocationSendLegacyPhoneRequest"
              },
              "regularBsuid": {
                "$ref": "#/components/examples/LocationSendRegularBsuidRequest"
              }
            }
          }
        }
      },
      "ContactCardMessageSend": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ContactCardMessageSendRequest"
            },
            "examples": {
              "legacyPhone": {
                "$ref": "#/components/examples/ContactCardSendLegacyPhoneRequest"
              },
              "regularBsuid": {
                "$ref": "#/components/examples/ContactCardSendRegularBsuidRequest"
              }
            }
          }
        }
      }
    },
    "responses": {
      "MessageAccepted": {
        "description": "Message accepted for asynchronous processing.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MessageAcceptedResponse"
            },
            "examples": {
              "legacyPhone": {
                "$ref": "#/components/examples/MessageAcceptedLive"
              },
              "typedRegularBsuid": {
                "$ref": "#/components/examples/TypedMessageAcceptedRegularBsuid"
              }
            }
          }
        }
      },
      "MessageMarkedRead": {
        "description": "Inbound message marked as read.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MarkReadResponse"
            }
          }
        }
      },
      "MessageList": {
        "description": "Paginated message list.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MessageListResponse"
            }
          }
        }
      },
      "MessageRetrieved": {
        "description": "Message found.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MessageRetrieveResponse"
            }
          }
        }
      },
      "SenderList": {
        "description": "Paginated Sender list.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/SenderListResponse"
            }
          }
        }
      },
      "TemplateList": {
        "description": "Paginated template list.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/TemplateListResponse"
            }
          }
        }
      },
      "MediaRetrieved": {
        "description": "Inbound media metadata and temporary download URL.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MediaRetrieveResponse"
            }
          }
        }
      },
      "EventList": {
        "description": "Paginated event list.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/EventListResponse"
            }
          }
        }
      },
      "EventRetrieved": {
        "description": "Event found.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/EventRetrieveResponse"
            }
          }
        }
      },
      "WebhookDeliveryList": {
        "description": "Paginated webhook delivery list.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/WebhookDeliveryListResponse"
            }
          }
        }
      },
      "WebhookDeliveryRetrieved": {
        "description": "Webhook delivery found.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/WebhookDeliveryRetrieveResponse"
            }
          }
        }
      },
      "WebhookDeliveryReplayAccepted": {
        "description": "Webhook replay accepted.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/WebhookDeliveryReplayResponse"
            }
          }
        }
      },
      "UsageList": {
        "description": "Paginated usage list.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UsageListResponse"
            }
          }
        }
      },
      "BadRequest": {
        "description": "Malformed request.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "malformedRequest": {
                "$ref": "#/components/examples/MalformedRequestError"
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid Yanola API Key.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "invalidApiKey": {
                "$ref": "#/components/examples/InvalidApiKeyError"
              }
            }
          }
        }
      },
      "InsufficientBalance": {
        "description": "Yanola Balance is too low for a usage-billed Live Mode action.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "insufficientBalance": {
                "$ref": "#/components/examples/InsufficientBalanceError"
              },
              "planMessageLimitReached": {
                "summary": "Plan message limit reached (Message Cap)",
                "value": {
                  "error": {
                    "type": "billing_error",
                    "code": "plan_message_limit_reached",
                    "message": "The monthly message cap for this plan has been reached.",
                    "requestId": "req_0123456789",
                    "retryable": false,
                    "details": {
                      "action": "wait_for_next_period_or_upgrade",
                      "limit": 1000,
                      "period_end": "2026-06-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Valid key without required scope, Sender access, or entitlement.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "recipientScopeMismatch": {
                "$ref": "#/components/examples/WhatsappRecipientScopeMismatchError"
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found in the Agent Project and environment.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "IdempotencyConflict": {
        "description": "Idempotency key reused with a different request body or conflicting state.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "idempotencyKeyReused": {
                "$ref": "#/components/examples/IdempotencyKeyReusedError"
              }
            }
          }
        }
      },
      "BusinessStateInvalid": {
        "description": "Valid JSON but invalid business state.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "serviceWindowRequired": {
                "$ref": "#/components/examples/ServiceWindowRequiredError"
              },
              "senderReconnectRequired": {
                "$ref": "#/components/examples/SenderReconnectRequiredError"
              },
              "routeCapabilityUnavailable": {
                "$ref": "#/components/examples/WhatsappRouteCapabilityUnavailableError"
              },
              "phoneOnlyTemplate": {
                "$ref": "#/components/examples/WhatsappPhoneOnlyTemplateError"
              },
              "templateCapabilityUnknown": {
                "$ref": "#/components/examples/WhatsappTemplateCapabilityUnknownError"
              },
              "sandboxQuotaExhausted": {
                "$ref": "#/components/examples/SandboxQuotaExhaustedError"
              },
              "sandboxMessageTypeUnsupported": {
                "$ref": "#/components/examples/SandboxMessageTypeUnsupportedError"
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "x-ratelimit-limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "x-ratelimit-remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "x-ratelimit-reset": {
            "$ref": "#/components/headers/RateLimitReset"
          },
          "retry-after": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "rateLimited": {
                "$ref": "#/components/examples/RateLimitedError"
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected server error.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "Yanola or provider service is temporarily unavailable.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "retry-after": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "Environment": {
        "type": "string",
        "enum": [
          "live",
          "test"
        ]
      },
      "DeliveryMode": {
        "type": "string",
        "description": "How Yanola produced and delivered the message lifecycle. simulated is synthetic Test Mode, sandbox is real-provider Test traffic through Yanola Sandbox, and live is customer-provider Live traffic.",
        "enum": [
          "live",
          "sandbox",
          "simulated"
        ]
      },
      "SandboxContext": {
        "type": "object",
        "description": "Privacy-safe identifiers for one Yanola Sandbox grant and session. Participant identity, join codes, credentials, and provider identifiers are never exposed.",
        "required": [
          "grantId",
          "sessionId"
        ],
        "properties": {
          "grantId": {
            "type": "string"
          },
          "sessionId": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "E164PhoneNumber": {
        "type": "string",
        "pattern": "^\\+[1-9]\\d{1,14}$",
        "example": "+15557654321"
      },
      "LiveMessageId": {
        "type": "string",
        "pattern": "^msg_[A-Za-z0-9]{24}$"
      },
      "TestMessageId": {
        "type": "string",
        "pattern": "^msg_test_[A-Za-z0-9]{24}$"
      },
      "PublicMessageId": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/LiveMessageId"
          },
          {
            "$ref": "#/components/schemas/TestMessageId"
          }
        ]
      },
      "EventId": {
        "type": "string",
        "pattern": "^evt_[A-Za-z0-9]{24}$"
      },
      "WebhookDeliveryId": {
        "type": "string",
        "pattern": "^del_[A-Za-z0-9]{24}$"
      },
      "ConversationId": {
        "type": "string",
        "pattern": "^conv_[A-Za-z0-9]{24}$"
      },
      "MediaId": {
        "type": "string",
        "pattern": "^med_[A-Za-z0-9]{24}$"
      },
      "UsageId": {
        "type": "string",
        "pattern": "^usg_[A-Za-z0-9]{24}$"
      },
      "UsageReservationId": {
        "type": "string",
        "pattern": "^resv_[A-Za-z0-9]{24}$"
      },
      "MessageType": {
        "type": "string",
        "enum": [
          "text",
          "template",
          "image",
          "video",
          "document",
          "audio",
          "location",
          "contact_card"
        ]
      },
      "MessageDirection": {
        "type": "string",
        "enum": [
          "inbound",
          "outbound"
        ]
      },
      "MessageStatus": {
        "type": "string",
        "enum": [
          "queued",
          "sending",
          "sent",
          "delivered",
          "read",
          "failed",
          "canceled",
          "needs_reconciliation"
        ]
      },
      "TextMessageSendRequest": {
        "description": "Exactly one complete request branch: the unchanged v1-compatible 'from' + 'to' phone shape, or 'from' + one typed 'recipient'. Both, neither, blank, malformed, and undeclared route fields are invalid.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PhoneTextMessageSendRequest"
          },
          {
            "$ref": "#/components/schemas/TypedTextMessageSendRequest"
          }
        ]
      },
      "TemplateMessageSendRequest": {
        "description": "Exactly one complete request branch: the unchanged v1-compatible 'from' + 'to' phone shape, or 'from' + one typed 'recipient'. Both, neither, blank, malformed, and undeclared route fields are invalid.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PhoneTemplateMessageSendRequest"
          },
          {
            "$ref": "#/components/schemas/TypedTemplateMessageSendRequest"
          }
        ]
      },
      "TemplateComponent": {
        "type": "object",
        "required": [
          "type",
          "parameters"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "header",
              "body",
              "button"
            ]
          },
          "subType": {
            "type": "string",
            "enum": [
              "quick_reply",
              "url"
            ]
          },
          "index": {
            "type": "integer",
            "minimum": 0
          },
          "parameters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateParameter"
            }
          }
        },
        "additionalProperties": false
      },
      "TemplateParameter": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "text",
              "currency",
              "date_time",
              "image",
              "video",
              "document",
              "payload"
            ]
          },
          "text": {
            "type": "string"
          },
          "payload": {
            "type": "string"
          },
          "mediaUrl": {
            "type": "string",
            "format": "uri"
          }
        },
        "additionalProperties": true
      },
      "MediaMessageSendRequest": {
        "description": "Exactly one complete request branch: the unchanged v1-compatible 'from' + 'to' phone shape, or 'from' + one typed 'recipient'. Both, neither, blank, malformed, and undeclared route fields are invalid.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PhoneMediaMessageSendRequest"
          },
          {
            "$ref": "#/components/schemas/TypedMediaMessageSendRequest"
          }
        ]
      },
      "LocationMessageSendRequest": {
        "description": "Exactly one complete request branch: the unchanged v1-compatible 'from' + 'to' phone shape, or 'from' + one typed 'recipient'. Both, neither, blank, malformed, and undeclared route fields are invalid.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PhoneLocationMessageSendRequest"
          },
          {
            "$ref": "#/components/schemas/TypedLocationMessageSendRequest"
          }
        ]
      },
      "ContactCardMessageSendRequest": {
        "description": "Exactly one complete request branch: the unchanged v1-compatible 'from' + 'to' phone shape, or 'from' + one typed 'recipient'. Both, neither, blank, malformed, and undeclared route fields are invalid.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PhoneContactCardMessageSendRequest"
          },
          {
            "$ref": "#/components/schemas/TypedContactCardMessageSendRequest"
          }
        ]
      },
      "ContactCard": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "object",
            "required": [
              "formattedName"
            ],
            "properties": {
              "formattedName": {
                "type": "string",
                "minLength": 1,
                "maxLength": 512
              },
              "firstName": {
                "type": "string"
              },
              "lastName": {
                "type": "string"
              }
            },
            "additionalProperties": false
          },
          "phones": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "phone"
              ],
              "properties": {
                "phone": {
                  "type": "string",
                  "minLength": 1
                },
                "type": {
                  "type": "string"
                }
              },
              "additionalProperties": false
            }
          },
          "emails": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "email"
              ],
              "properties": {
                "email": {
                  "type": "string",
                  "format": "email"
                },
                "type": {
                  "type": "string"
                }
              },
              "additionalProperties": false
            }
          },
          "org": {
            "type": "object",
            "properties": {
              "company": {
                "type": "string"
              },
              "department": {
                "type": "string"
              },
              "title": {
                "type": "string"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "MessageAcceptedResponse": {
        "description": "The legacy request branch retains the exact v1 accepted response. The typed branch returns the selected typed recipient and a nullable legacy phone projection.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PhoneMessageAcceptedResponse"
          },
          {
            "$ref": "#/components/schemas/TypedMessageAcceptedResponse"
          }
        ]
      },
      "Message": {
        "type": "object",
        "required": [
          "id",
          "environment",
          "direction",
          "type",
          "status",
          "from",
          "to",
          "createdAt",
          "fromIdentity",
          "toIdentity",
          "customer"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PublicMessageId"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "direction": {
            "$ref": "#/components/schemas/MessageDirection"
          },
          "type": {
            "$ref": "#/components/schemas/MessageType"
          },
          "status": {
            "$ref": "#/components/schemas/MessageStatus"
          },
          "from": {
            "$ref": "#/components/schemas/NullableE164PhoneNumber"
          },
          "to": {
            "$ref": "#/components/schemas/NullableE164PhoneNumber"
          },
          "conversationId": {
            "$ref": "#/components/schemas/ConversationId"
          },
          "source": {
            "type": "string",
            "enum": [
              "api",
              "workflow",
              "dashboard",
              "inbound",
              "test"
            ]
          },
          "text": {
            "type": [
              "string",
              "null"
            ]
          },
          "failure": {
            "$ref": "#/components/schemas/FailureSummary"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "fromIdentity": {
            "$ref": "#/components/schemas/PublicWhatsAppRecipient"
          },
          "toIdentity": {
            "$ref": "#/components/schemas/PublicWhatsAppRecipient"
          },
          "customer": {
            "$ref": "#/components/schemas/NullableCanonicalCustomerReference"
          }
        },
        "additionalProperties": false,
        "description": "A v1 normalized message. Typed endpoint identities are required; from and to are nullable phone projections and never contain a BSUID or username."
      },
      "FailureSummary": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "retryable": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "MarkReadResponse": {
        "type": "object",
        "required": [
          "id",
          "status",
          "requestId"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PublicMessageId"
          },
          "status": {
            "type": "string",
            "const": "read"
          },
          "requestId": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "Pagination": {
        "type": "object",
        "required": [
          "hasMore"
        ],
        "properties": {
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "MessageListResponse": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Message"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "additionalProperties": false
      },
      "MessageRetrieveResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Message"
          }
        },
        "additionalProperties": false
      },
      "Sender": {
        "type": "object",
        "required": [
          "phoneNumber",
          "displayName",
          "status",
          "apiEligible"
        ],
        "properties": {
          "phoneNumber": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "displayName": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive",
              "pending_verification",
              "suspended",
              "reconnect_required"
            ]
          },
          "apiEligible": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "SenderListResponse": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Sender"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "additionalProperties": false
      },
      "Template": {
        "type": "object",
        "required": [
          "name",
          "languageCode",
          "status",
          "category",
          "components",
          "syncedAt"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "languageCode": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "approved",
              "paused",
              "disabled"
            ]
          },
          "category": {
            "type": "string"
          },
          "components": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateCatalogComponent"
            }
          },
          "syncedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "TemplateCatalogComponent": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "format": {
            "type": "string"
          },
          "example": {}
        },
        "additionalProperties": true
      },
      "TemplateListResponse": {
        "type": "object",
        "required": [
          "data",
          "pagination",
          "sender",
          "syncedAt"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Template"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "sender": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "syncedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "MediaRetrieveResponse": {
        "type": "object",
        "required": [
          "id",
          "environment",
          "mimeType",
          "downloadUrl",
          "expiresAt"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/MediaId"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "mimeType": {
            "type": "string"
          },
          "filename": {
            "type": [
              "string",
              "null"
            ]
          },
          "sizeBytes": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "downloadUrl": {
            "type": "string",
            "format": "uri"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "EventType": {
        "type": "string",
        "enum": [
          "yanola.webhook.test",
          "whatsapp.message.received",
          "whatsapp.message.sent",
          "whatsapp.conversation.started",
          "whatsapp.message.delivered",
          "whatsapp.message.read",
          "whatsapp.message.failed",
          "whatsapp.customer.identity.updated"
        ]
      },
      "Event": {
        "description": "The v1 normalized event union. The type discriminator selects a message/status, conversation, identity lifecycle, or test payload.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/MessageEvent"
          },
          {
            "$ref": "#/components/schemas/ConversationStartedEvent"
          },
          {
            "$ref": "#/components/schemas/CustomerIdentityUpdatedEvent"
          },
          {
            "$ref": "#/components/schemas/WebhookTestEvent"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "whatsapp.message.received": "#/components/schemas/MessageEvent",
            "whatsapp.message.sent": "#/components/schemas/MessageEvent",
            "whatsapp.message.delivered": "#/components/schemas/MessageEvent",
            "whatsapp.message.read": "#/components/schemas/MessageEvent",
            "whatsapp.message.failed": "#/components/schemas/MessageEvent",
            "whatsapp.conversation.started": "#/components/schemas/ConversationStartedEvent",
            "whatsapp.customer.identity.updated": "#/components/schemas/CustomerIdentityUpdatedEvent",
            "yanola.webhook.test": "#/components/schemas/WebhookTestEvent"
          }
        }
      },
      "EventData": {
        "type": "object",
        "description": "Yanola-normalized event data. Additional normalized fields may be added compatibly. Raw provider payloads, raw-payload storage references, provider credentials, provider IDs, and internal database IDs are never exposed by event read endpoints.",
        "properties": {
          "deliveryMode": {
            "$ref": "#/components/schemas/DeliveryMode"
          },
          "sandboxSessionId": {
            "type": [
              "string",
              "null"
            ]
          },
          "sandbox": {
            "$ref": "#/components/schemas/SandboxContext"
          },
          "message": {
            "$ref": "#/components/schemas/Message"
          },
          "sender": {
            "$ref": "#/components/schemas/Sender"
          },
          "conversation": {
            "type": "object",
            "properties": {
              "id": {
                "$ref": "#/components/schemas/ConversationId"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": true
      },
      "EventListResponse": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "additionalProperties": false
      },
      "EventRetrieveResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Event"
          }
        },
        "additionalProperties": false
      },
      "YanolaWebhookPayload": {
        "description": "The normalized v1 typed-identity webhook body.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Event"
          }
        ]
      },
      "RawProviderPayload": {
        "type": "object",
        "description": "A retained, tenant-scoped provider payload. It is present only while the account entitlement and retention window allow access.",
        "required": [
          "provider",
          "payloadType",
          "providerPayload"
        ],
        "properties": {
          "provider": {
            "type": "string",
            "example": "meta_whatsapp"
          },
          "payloadType": {
            "type": "string",
            "example": "webhook"
          },
          "providerPayload": {}
        },
        "additionalProperties": false
      },
      "YanolaWebhookPayloadWithRaw": {
        "description": "The normalized v1 typed-identity event plus retained raw provider data when available.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Event"
          },
          {
            "type": "object",
            "required": [
              "raw"
            ],
            "properties": {
              "raw": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/RawProviderPayload"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        ]
      },
      "MetaWebhookMetadata": {
        "type": "object",
        "required": [
          "display_phone_number",
          "phone_number_id"
        ],
        "properties": {
          "display_phone_number": {
            "type": "string"
          },
          "phone_number_id": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "MetaWebhookValue": {
        "type": "object",
        "required": [
          "messaging_product",
          "metadata"
        ],
        "properties": {
          "messaging_product": {
            "type": "string",
            "const": "whatsapp"
          },
          "metadata": {
            "$ref": "#/components/schemas/MetaWebhookMetadata"
          },
          "contacts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "statuses": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "additionalProperties": true
      },
      "MetaWebhookPayload": {
        "type": "object",
        "description": "An unwrapped Meta-compatible WhatsApp webhook JSON body. Yanola narrows a retained Meta batch to the triggering Developer Event when possible and otherwise synthesizes the same structural shape from normalized data. This is not a byte-for-byte replay of Meta's original HTTP request.",
        "required": [
          "object",
          "entry"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "whatsapp_business_account"
          },
          "entry": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "changes"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "changes": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "field",
                      "value"
                    ],
                    "properties": {
                      "field": {
                        "type": "string"
                      },
                      "value": {
                        "$ref": "#/components/schemas/MetaWebhookValue"
                      }
                    },
                    "additionalProperties": false
                  }
                }
              },
              "additionalProperties": false
            }
          }
        },
        "additionalProperties": false
      },
      "WebhookDeliveryStatus": {
        "type": "string",
        "enum": [
          "pending",
          "delivering",
          "succeeded",
          "failed",
          "canceled"
        ]
      },
      "WebhookPayloadFormat": {
        "type": "string",
        "enum": [
          "yanola",
          "meta",
          "yanola_with_raw"
        ]
      },
      "WebhookDelivery": {
        "type": "object",
        "required": [
          "id",
          "eventId",
          "environment",
          "status",
          "attemptCount",
          "payloadFormat",
          "lastAttemptAt",
          "nextAttemptAt",
          "responseStatus",
          "responsePreview",
          "replayed",
          "createdAt"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/WebhookDeliveryId"
          },
          "eventId": {
            "$ref": "#/components/schemas/EventId"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "status": {
            "$ref": "#/components/schemas/WebhookDeliveryStatus"
          },
          "attemptCount": {
            "type": "integer",
            "minimum": 0
          },
          "payloadFormat": {
            "$ref": "#/components/schemas/WebhookPayloadFormat"
          },
          "lastAttemptAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "nextAttemptAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "responseStatus": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 100,
            "maximum": 599
          },
          "responsePreview": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1024,
            "description": "A bounded, defensively redacted preview of the latest endpoint response. Headers, credentials, endpoint identifiers, and full response bodies are not exposed."
          },
          "replayed": {
            "type": "boolean",
            "default": false
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "WebhookDeliveryListResponse": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "additionalProperties": false
      },
      "WebhookDeliveryRetrieveResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/WebhookDelivery"
          }
        },
        "additionalProperties": false
      },
      "WebhookDeliveryReplayResponse": {
        "type": "object",
        "required": [
          "id",
          "eventId",
          "status",
          "replayed",
          "requestId"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/WebhookDeliveryId"
          },
          "eventId": {
            "$ref": "#/components/schemas/EventId"
          },
          "status": {
            "type": "string",
            "const": "pending"
          },
          "replayed": {
            "type": "boolean",
            "const": true
          },
          "requestId": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "UsageStatus": {
        "type": "string",
        "enum": [
          "reserved",
          "released",
          "finalized",
          "needs_reconciliation"
        ]
      },
      "UsageRecord": {
        "type": "object",
        "required": [
          "id",
          "environment",
          "status",
          "currency",
          "estimatedAmount",
          "totalAmount",
          "createdAt"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UsageId"
          },
          "reservationId": {
            "$ref": "#/components/schemas/UsageReservationId"
          },
          "messageId": {
            "$ref": "#/components/schemas/PublicMessageId"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "status": {
            "$ref": "#/components/schemas/UsageStatus"
          },
          "providerCategory": {
            "type": [
              "string",
              "null"
            ]
          },
          "market": {
            "type": [
              "string",
              "null"
            ]
          },
          "currency": {
            "type": "string",
            "const": "USD"
          },
          "estimatedAmount": {
            "type": "string",
            "pattern": "^\\d+\\.\\d{2,6}$",
            "description": "Amount reserved or estimated when the message was accepted."
          },
          "providerAmount": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d+\\.\\d{2,6}$",
            "description": "Provider pass-through amount from the latest immutable pricing snapshot, when available."
          },
          "yanolaFee": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d+\\.\\d{2,6}$",
            "description": "Yanola fee from the latest immutable pricing snapshot, when available."
          },
          "totalAmount": {
            "type": "string",
            "pattern": "^\\d+\\.\\d{2,6}$",
            "description": "Finalized Yanola Balance charge. Zero for reserved, released, and needs_reconciliation records."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "finalizedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "UsageListResponse": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsageRecord"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "additionalProperties": false
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorObject"
          }
        },
        "additionalProperties": false
      },
      "ErrorObject": {
        "type": "object",
        "required": [
          "type",
          "code",
          "message",
          "requestId",
          "retryable",
          "details"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "invalid_request_error",
              "authentication_error",
              "permission_error",
              "billing_error",
              "idempotency_error",
              "business_state_error",
              "rate_limit_error",
              "provider_error",
              "api_error"
            ]
          },
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "requestId": {
            "type": "string"
          },
          "retryable": {
            "type": "boolean"
          },
          "details": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "additionalProperties": false
      },
      "PhoneTextMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "to",
          "body"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "to": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4096
          },
          "previewUrl": {
            "type": "boolean",
            "default": false
          }
        },
        "additionalProperties": false
      },
      "PhoneTemplateMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "to",
          "name",
          "languageCode"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "to": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512
          },
          "languageCode": {
            "type": "string",
            "minLength": 2,
            "maxLength": 16,
            "example": "en_US"
          },
          "components": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateComponent"
            },
            "default": []
          }
        },
        "additionalProperties": false
      },
      "PhoneMediaMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "to",
          "type",
          "mediaUrl"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "to": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "type": {
            "type": "string",
            "enum": [
              "image",
              "video",
              "document",
              "audio"
            ]
          },
          "mediaUrl": {
            "type": "string",
            "format": "uri"
          },
          "caption": {
            "type": "string",
            "maxLength": 1024
          },
          "filename": {
            "type": "string",
            "maxLength": 255
          }
        },
        "additionalProperties": false
      },
      "PhoneLocationMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "to",
          "latitude",
          "longitude"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "to": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "latitude": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "longitude": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "name": {
            "type": "string",
            "maxLength": 1000
          },
          "address": {
            "type": "string",
            "maxLength": 1000
          }
        },
        "additionalProperties": false
      },
      "PhoneContactCardMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "to",
          "contacts"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "to": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "contacts": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/ContactCard"
            }
          }
        },
        "additionalProperties": false
      },
      "PhoneMessageAcceptedResponse": {
        "type": "object",
        "required": [
          "id",
          "environment",
          "status",
          "from",
          "to",
          "requestId",
          "createdAt"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PublicMessageId"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "status": {
            "type": "string",
            "const": "queued"
          },
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "to": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "requestId": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "PhoneRecipient": {
        "type": "object",
        "description": "A customer phone route. The phone number remains strictly E.164.",
        "required": [
          "kind",
          "phoneNumber"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "const": "phone"
          },
          "phoneNumber": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          }
        },
        "additionalProperties": false
      },
      "RegularBsuidRecipient": {
        "type": "object",
        "description": "A regular Meta Business-scoped user ID. Yanola derives and verifies the owning Business Portfolio from the authenticated Agent Project and the selected 'from' Sender; clients cannot supply or widen that scope.",
        "required": [
          "kind",
          "userId"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "const": "regular_bsuid"
          },
          "userId": {
            "type": "string",
            "pattern": "^[A-Z]{2}\\.[A-Za-z0-9]{1,128}$",
            "maxLength": 131,
            "example": "US.10000000000000000001"
          }
        },
        "additionalProperties": false
      },
      "ParentBsuidRecipient": {
        "type": "object",
        "description": "A parent Meta Business-scoped user ID. The parent account and enrolled Business Portfolio are server-derived. This route is syntactically reserved but remains disabled until Yanola records verified Meta eligibility and portfolio enrollment.",
        "required": [
          "kind",
          "parentUserId"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "const": "parent_bsuid"
          },
          "parentUserId": {
            "type": "string",
            "pattern": "^[A-Z]{2}\\.ENT\\.[A-Za-z0-9]{1,128}$",
            "maxLength": 135,
            "example": "US.ENT.20000000000000000001"
          }
        },
        "additionalProperties": false
      },
      "PublicWhatsAppRecipient": {
        "description": "Exactly one typed recipient. Business Portfolio, tenant, canonical customer, and parent-account scope are deliberately absent and server-derived from the API key and verified 'from' Sender ownership.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PhoneRecipient"
          },
          {
            "$ref": "#/components/schemas/RegularBsuidRecipient"
          },
          {
            "$ref": "#/components/schemas/ParentBsuidRecipient"
          }
        ],
        "discriminator": {
          "propertyName": "kind",
          "mapping": {
            "phone": "#/components/schemas/PhoneRecipient",
            "regular_bsuid": "#/components/schemas/RegularBsuidRecipient",
            "parent_bsuid": "#/components/schemas/ParentBsuidRecipient"
          }
        }
      },
      "NullableE164PhoneNumber": {
        "description": "A legacy phone projection. It is null when Meta supplied no phone for the typed recipient; it never contains a BSUID, username, or empty string.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          {
            "type": "null"
          }
        ]
      },
      "TypedTextMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "recipient",
          "body"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4096
          },
          "previewUrl": {
            "type": "boolean",
            "default": false
          },
          "recipient": {
            "$ref": "#/components/schemas/PublicWhatsAppRecipient"
          }
        },
        "additionalProperties": false,
        "description": "Typed-recipient branch. It rejects 'to' and every undeclared scope or route field."
      },
      "TypedTemplateMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "recipient",
          "name",
          "languageCode"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512
          },
          "languageCode": {
            "type": "string",
            "minLength": 2,
            "maxLength": 16,
            "example": "en_US"
          },
          "components": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateComponent"
            },
            "default": []
          },
          "recipient": {
            "$ref": "#/components/schemas/PublicWhatsAppRecipient"
          }
        },
        "additionalProperties": false,
        "description": "Typed-recipient branch. It rejects 'to' and every undeclared scope or route field."
      },
      "TypedMediaMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "recipient",
          "type",
          "mediaUrl"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "type": {
            "type": "string",
            "enum": [
              "image",
              "video",
              "document",
              "audio"
            ]
          },
          "mediaUrl": {
            "type": "string",
            "format": "uri"
          },
          "caption": {
            "type": "string",
            "maxLength": 1024
          },
          "filename": {
            "type": "string",
            "maxLength": 255
          },
          "recipient": {
            "$ref": "#/components/schemas/PublicWhatsAppRecipient"
          }
        },
        "additionalProperties": false,
        "description": "Typed-recipient branch. It rejects 'to' and every undeclared scope or route field."
      },
      "TypedLocationMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "recipient",
          "latitude",
          "longitude"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "latitude": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "longitude": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "name": {
            "type": "string",
            "maxLength": 1000
          },
          "address": {
            "type": "string",
            "maxLength": 1000
          },
          "recipient": {
            "$ref": "#/components/schemas/PublicWhatsAppRecipient"
          }
        },
        "additionalProperties": false,
        "description": "Typed-recipient branch. It rejects 'to' and every undeclared scope or route field."
      },
      "TypedContactCardMessageSendRequest": {
        "type": "object",
        "required": [
          "from",
          "recipient",
          "contacts"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/E164PhoneNumber"
          },
          "contacts": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/ContactCard"
            }
          },
          "recipient": {
            "$ref": "#/components/schemas/PublicWhatsAppRecipient"
          }
        },
        "additionalProperties": false,
        "description": "Typed-recipient branch. It rejects 'to' and every undeclared scope or route field."
      },
      "TypedMessageAcceptedResponse": {
        "type": "object",
        "description": "Accepted response for a typed-recipient request. 'to' is a nullable phone projection and is null for BSUID-only recipients.",
        "required": [
          "id",
          "environment",
          "status",
          "from",
          "to",
          "recipient",
          "requestId",
          "createdAt"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PublicMessageId"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "status": {
            "type": "string",
            "const": "queued"
          },
          "from": {
            "allOf": [
              {
                "$ref": "#/components/schemas/E164PhoneNumber"
              }
            ],
            "description": "The business Sender phone asset used for this send."
          },
          "to": {
            "$ref": "#/components/schemas/NullableE164PhoneNumber"
          },
          "recipient": {
            "$ref": "#/components/schemas/PublicWhatsAppRecipient"
          },
          "requestId": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "CanonicalCustomerReference": {
        "type": "object",
        "description": "A stable tenant-scoped Yanola customer reference. It does not change when a provider alias rotates.",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "additionalProperties": false
      },
      "NullableCanonicalCustomerReference": {
        "description": "Null only for legacy phone history that predates canonical identity adoption.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/CanonicalCustomerReference"
          },
          {
            "type": "null"
          }
        ]
      },
      "RegularBsuidIdentityChange": {
        "type": "object",
        "required": [
          "kind",
          "previousIdentity",
          "currentIdentity"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "const": "regular_bsuid"
          },
          "previousIdentity": {
            "$ref": "#/components/schemas/RegularBsuidRecipient"
          },
          "currentIdentity": {
            "$ref": "#/components/schemas/RegularBsuidRecipient"
          }
        },
        "additionalProperties": false
      },
      "ParentBsuidIdentityChange": {
        "type": "object",
        "required": [
          "kind",
          "previousIdentity",
          "currentIdentity"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "const": "parent_bsuid"
          },
          "previousIdentity": {
            "$ref": "#/components/schemas/ParentBsuidRecipient"
          },
          "currentIdentity": {
            "$ref": "#/components/schemas/ParentBsuidRecipient"
          }
        },
        "additionalProperties": false
      },
      "PublicIdentityChange": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/RegularBsuidIdentityChange"
          },
          {
            "$ref": "#/components/schemas/ParentBsuidIdentityChange"
          }
        ],
        "discriminator": {
          "propertyName": "kind",
          "mapping": {
            "regular_bsuid": "#/components/schemas/RegularBsuidIdentityChange",
            "parent_bsuid": "#/components/schemas/ParentBsuidIdentityChange"
          }
        }
      },
      "IdentityChange": {
        "type": "object",
        "description": "Immutable event-time alias rotation evidence. Consumers update routing aliases but keep the canonical customer reference.",
        "required": [
          "reason",
          "source",
          "changes",
          "occurredAt"
        ],
        "properties": {
          "reason": {
            "type": "string",
            "const": "provider_alias_rotated"
          },
          "source": {
            "type": "string",
            "const": "user_id_update"
          },
          "changes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 2,
            "items": {
              "$ref": "#/components/schemas/PublicIdentityChange"
            }
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "MessageEventData": {
        "type": "object",
        "required": [
          "message",
          "customer"
        ],
        "properties": {
          "deliveryMode": {
            "$ref": "#/components/schemas/DeliveryMode"
          },
          "sandboxSessionId": {
            "type": [
              "string",
              "null"
            ]
          },
          "sandbox": {
            "$ref": "#/components/schemas/SandboxContext"
          },
          "message": {
            "$ref": "#/components/schemas/Message"
          },
          "customer": {
            "$ref": "#/components/schemas/NullableCanonicalCustomerReference"
          },
          "sender": {
            "$ref": "#/components/schemas/Sender"
          },
          "conversation": {
            "type": "object",
            "required": [
              "id"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/ConversationId"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": true
      },
      "IdentityUpdatedEventData": {
        "type": "object",
        "required": [
          "customer",
          "identityChange"
        ],
        "properties": {
          "customer": {
            "$ref": "#/components/schemas/CanonicalCustomerReference"
          },
          "identityChange": {
            "$ref": "#/components/schemas/IdentityChange"
          }
        },
        "additionalProperties": true
      },
      "MessageEvent": {
        "type": "object",
        "required": [
          "id",
          "type",
          "environment",
          "createdAt",
          "data"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/EventId"
          },
          "type": {
            "type": "string",
            "enum": [
              "whatsapp.message.received",
              "whatsapp.message.sent",
              "whatsapp.message.delivered",
              "whatsapp.message.read",
              "whatsapp.message.failed"
            ]
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "deliveryMode": {
            "$ref": "#/components/schemas/DeliveryMode"
          },
          "sandbox": {
            "$ref": "#/components/schemas/SandboxContext"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/MessageEventData"
          }
        },
        "additionalProperties": true
      },
      "ConversationStartedEvent": {
        "type": "object",
        "required": [
          "id",
          "type",
          "environment",
          "createdAt",
          "data"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/EventId"
          },
          "type": {
            "type": "string",
            "const": "whatsapp.conversation.started"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "deliveryMode": {
            "$ref": "#/components/schemas/DeliveryMode"
          },
          "sandbox": {
            "$ref": "#/components/schemas/SandboxContext"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/MessageEventData"
          }
        },
        "additionalProperties": true
      },
      "CustomerIdentityUpdatedEvent": {
        "type": "object",
        "required": [
          "id",
          "type",
          "environment",
          "createdAt",
          "data"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/EventId"
          },
          "type": {
            "type": "string",
            "const": "whatsapp.customer.identity.updated"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "deliveryMode": {
            "$ref": "#/components/schemas/DeliveryMode"
          },
          "sandbox": {
            "$ref": "#/components/schemas/SandboxContext"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/IdentityUpdatedEventData"
          }
        },
        "additionalProperties": true
      },
      "WebhookTestEvent": {
        "type": "object",
        "required": [
          "id",
          "type",
          "environment",
          "createdAt",
          "data"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/EventId"
          },
          "type": {
            "type": "string",
            "const": "yanola.webhook.test"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "deliveryMode": {
            "$ref": "#/components/schemas/DeliveryMode"
          },
          "sandbox": {
            "$ref": "#/components/schemas/SandboxContext"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/EventData"
          }
        },
        "additionalProperties": true
      }
    },
    "examples": {
      "MessageAcceptedLive": {
        "summary": "Live Mode accepted response",
        "value": {
          "id": "msg_0123456789ABCDEabcdeWXYZ",
          "environment": "live",
          "status": "queued",
          "from": "+15557654321",
          "to": "+15551234567",
          "requestId": "req_0123456789",
          "createdAt": "2026-07-21T12:00:00.000Z"
        }
      },
      "SandboxQuotaExhaustedError": {
        "summary": "Yanola Sandbox provider-attempt quota is exhausted",
        "value": {
          "error": {
            "type": "business_state_error",
            "code": "sandbox_quota_exhausted",
            "message": "The Sandbox monthly provider-attempt quota is exhausted.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {
              "limit": 100,
              "resetsAt": "2026-11-01T00:00:00.000Z"
            }
          }
        }
      },
      "SandboxMessageTypeUnsupportedError": {
        "summary": "Message type is not supported by Yanola Sandbox",
        "value": {
          "error": {
            "type": "business_state_error",
            "code": "sandbox_message_type_unsupported",
            "message": "Templates are not supported in Yanola Sandbox.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {
              "supportedMessageTypes": [
                "text",
                "image",
                "video",
                "document",
                "audio",
                "location",
                "contact_card"
              ]
            }
          }
        }
      },
      "MalformedRequestError": {
        "value": {
          "error": {
            "type": "invalid_request_error",
            "code": "malformed_request",
            "message": "The request body could not be parsed as JSON.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {}
          }
        }
      },
      "InvalidApiKeyError": {
        "value": {
          "error": {
            "type": "authentication_error",
            "code": "invalid_api_key",
            "message": "Invalid Yanola API Key.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {}
          }
        }
      },
      "InsufficientBalanceError": {
        "value": {
          "error": {
            "type": "billing_error",
            "code": "insufficient_balance",
            "message": "Your Yanola Balance is too low to send this message.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {
              "currency": "USD",
              "requiredAmount": "0.014000",
              "availableAmount": "0.000000"
            }
          }
        }
      },
      "IdempotencyKeyReusedError": {
        "value": {
          "error": {
            "type": "idempotency_error",
            "code": "idempotency_key_reused",
            "message": "This Idempotency-Key was already used with a different request body.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {}
          }
        }
      },
      "ServiceWindowRequiredError": {
        "value": {
          "error": {
            "type": "business_state_error",
            "code": "service_window_required",
            "message": "A text, media, location, or contact-card message requires an active Customer Service Window. Send an approved template instead.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {
              "from": "+15557654321",
              "to": "+15551234567"
            }
          }
        }
      },
      "SenderReconnectRequiredError": {
        "value": {
          "error": {
            "type": "business_state_error",
            "code": "sender_reconnect_required",
            "message": "Reconnect this Sender in Yanola before retrying.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {
              "action": "reconnect_sender"
            }
          }
        }
      },
      "RateLimitedError": {
        "value": {
          "error": {
            "type": "rate_limit_error",
            "code": "rate_limit_exceeded",
            "message": "Rate limit exceeded. Retry after the time in the retry-after header.",
            "requestId": "req_0123456789",
            "retryable": true,
            "details": {}
          }
        }
      },
      "TextSendLegacyPhoneRequest": {
        "summary": "Unchanged legacy phone request on /v1",
        "value": {
          "from": "+15557654321",
          "to": "+15551234567",
          "body": "Legacy phone clients can migrate the base path first.",
          "previewUrl": false
        }
      },
      "TextSendTypedPhoneRequest": {
        "summary": "Typed phone recipient",
        "value": {
          "from": "+15557654321",
          "recipient": {
            "kind": "phone",
            "phoneNumber": "+15551234567"
          },
          "body": "Typed phone route"
        }
      },
      "TextSendRegularBsuidRequest": {
        "summary": "Regular BSUID recipient",
        "value": {
          "from": "+15557654321",
          "recipient": {
            "kind": "regular_bsuid",
            "userId": "US.10000000000000000001"
          },
          "body": "Hello without a customer phone"
        }
      },
      "TextSendParentBsuidRequest": {
        "summary": "Parent BSUID syntax; capability remains disabled by default",
        "value": {
          "from": "+15557654321",
          "recipient": {
            "kind": "parent_bsuid",
            "parentUserId": "US.ENT.20000000000000000001"
          },
          "body": "Reserved parent route example"
        }
      },
      "TemplateSendLegacyPhoneRequest": {
        "summary": "Legacy phone template request",
        "value": {
          "from": "+15557654321",
          "to": "+15551234567",
          "name": "order_update",
          "languageCode": "en_US",
          "components": [
            {
              "type": "body",
              "parameters": [
                {
                  "type": "text",
                  "text": "A123"
                }
              ]
            }
          ]
        }
      },
      "TemplateSendRegularBsuidRequest": {
        "summary": "Trusted utility template to a regular BSUID",
        "value": {
          "from": "+15557654321",
          "recipient": {
            "kind": "regular_bsuid",
            "userId": "US.10000000000000000001"
          },
          "name": "order_update",
          "languageCode": "en_US",
          "components": [
            {
              "type": "body",
              "parameters": [
                {
                  "type": "text",
                  "text": "A123"
                }
              ]
            }
          ]
        }
      },
      "MediaSendLegacyPhoneRequest": {
        "summary": "Legacy phone media request",
        "value": {
          "from": "+15557654321",
          "to": "+15551234567",
          "type": "image",
          "mediaUrl": "https://cdn.example.com/order.png",
          "caption": "Your receipt"
        }
      },
      "MediaSendRegularBsuidRequest": {
        "summary": "Image to a regular BSUID",
        "value": {
          "from": "+15557654321",
          "recipient": {
            "kind": "regular_bsuid",
            "userId": "US.10000000000000000001"
          },
          "type": "image",
          "mediaUrl": "https://cdn.example.com/order.png",
          "caption": "Your receipt"
        }
      },
      "LocationSendLegacyPhoneRequest": {
        "summary": "Legacy phone location request",
        "value": {
          "from": "+15557654321",
          "to": "+15551234567",
          "latitude": 25.2048,
          "longitude": 55.2708,
          "name": "Yanola Dubai"
        }
      },
      "LocationSendRegularBsuidRequest": {
        "summary": "Location to a regular BSUID",
        "value": {
          "from": "+15557654321",
          "recipient": {
            "kind": "regular_bsuid",
            "userId": "US.10000000000000000001"
          },
          "latitude": 25.2048,
          "longitude": 55.2708,
          "name": "Yanola Dubai"
        }
      },
      "ContactCardSendLegacyPhoneRequest": {
        "summary": "Legacy phone contact-card request",
        "value": {
          "from": "+15557654321",
          "to": "+15551234567",
          "contacts": [
            {
              "name": {
                "formattedName": "Ada Lovelace"
              }
            }
          ]
        }
      },
      "ContactCardSendRegularBsuidRequest": {
        "summary": "Contact card to a regular BSUID",
        "value": {
          "from": "+15557654321",
          "recipient": {
            "kind": "regular_bsuid",
            "userId": "US.10000000000000000001"
          },
          "contacts": [
            {
              "name": {
                "formattedName": "Ada Lovelace"
              }
            }
          ]
        }
      },
      "TypedMessageAcceptedRegularBsuid": {
        "summary": "Accepted regular-BSUID send with no customer phone projection",
        "value": {
          "id": "msg_0123456789ABCDEabcdeWXYZ",
          "environment": "live",
          "status": "queued",
          "from": "+15557654321",
          "to": null,
          "recipient": {
            "kind": "regular_bsuid",
            "userId": "US.10000000000000000001"
          },
          "requestId": "req_0123456789",
          "createdAt": "2026-08-12T12:00:00.000Z"
        }
      },
      "WhatsappRouteCapabilityUnavailableError": {
        "summary": "BSUID route is not enabled for this account and Sender",
        "value": {
          "error": {
            "type": "business_state_error",
            "code": "whatsapp_route_capability_unavailable",
            "message": "The selected WhatsApp route or message capability is unavailable. Re-resolve or change the request before retrying.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {
              "recipientKind": "regular_bsuid"
            }
          }
        }
      },
      "WhatsappPhoneOnlyTemplateError": {
        "summary": "Authentication template requires an explicit phone route",
        "value": {
          "error": {
            "type": "business_state_error",
            "code": "whatsapp_phone_only_template",
            "message": "This authentication template is phone-only. Use a supported message or obtain a verified phone route.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {
              "recipientKind": "regular_bsuid"
            }
          }
        }
      },
      "WhatsappTemplateCapabilityUnknownError": {
        "summary": "Template capability is not trusted for BSUID routing",
        "value": {
          "error": {
            "type": "business_state_error",
            "code": "whatsapp_template_recipient_capability_unknown",
            "message": "This template has no trusted BSUID capability classification and cannot be sent to a WhatsApp user ID.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {
              "recipientKind": "regular_bsuid"
            }
          }
        }
      },
      "WhatsappRecipientScopeMismatchError": {
        "summary": "Recipient does not belong to the verified Sender portfolio scope",
        "value": {
          "error": {
            "type": "permission_error",
            "code": "whatsapp_recipient_scope_mismatch",
            "message": "The recipient cannot be used with this Sender and authenticated Agent Project.",
            "requestId": "req_0123456789",
            "retryable": false,
            "details": {}
          }
        }
      }
    }
  }
}
