{
  "openapi": "3.1.0",
  "info": {
    "title": "Waplify Public API",
    "version": "1.0.0",
    "description": "Send WhatsApp messages and manage templates, contacts, groups, campaigns, conversation assignment and chatbot flows from your own software. Every endpoint is under /api/v1/ and authenticates with an API key. Guides and webhook documentation: https://docs.waplify.io/api/overview",
    "contact": {
      "name": "Waplify Support",
      "email": "support@waplify.io",
      "url": "https://waplify.io/contact-us/"
    }
  },
  "servers": [
    {
      "url": "https://server.waplify.io",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Waplify API documentation",
    "url": "https://docs.waplify.io/api/overview"
  },
  "tags": [],
  "paths": {
    "/api/v1/messages/send": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Send message via API",
        "description": "Send a WhatsApp message using a template directly (no campaign required).\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`\n\n    **Rate Limiting:**\n    - Rate limits are enforced per API key\n    - Check response headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`\n    - Returns 429 Too Many Requests when limit exceeded\n\n    **Example Request:**\n    ```\n    POST /api/v1/messages/send\n    Authorization: Bearer wapl_1234567890abcdef\n    Content-Type: application/json\n\n    {\n        \"template_name\": \"order_confirmation\",\n        \"contact_phone\": \"+1234567890\",\n        \"contact_name\": \"John Doe\",\n        \"body_data\": {\n            \"1\": \"John\",\n            \"2\": \"Premium Plan\",\n            \"3\": \"$99\"\n        }\n    }\n    ```\n\n    **URL buttons with a variable:**\n    A \"Visit website\" button whose URL ends in a variable (e.g.\n    `https://shop.example.com/track?id={{1}}`) needs a value at send time. A\n    URL button carries exactly one variable, so `url_button_data` takes the\n    value directly:\n\n    ```\n    {\n        \"template_name\": \"order_shipped\",\n        \"contact_phone\": \"+1234567890\",\n        \"body_data\": {\"1\": \"John\"},\n        \"url_button_data\": \"ORD-12345\"\n    }\n    ```\n\n    A template may carry a second URL button; address them individually with\n    an object keyed by button position - `{\"0\": \"ORD-12345\", \"1\": \"REF-99\"}`.\n    A key naming the URL variable (`{\"order_id\": \"...\"}`) and a list in button\n    order (`[\"ORD-12345\"]`) work too. A numeric key is read as a 0-based\n    position first, so `\"1\"` means the second button when that button is the\n    dynamic one.\n\n    Pass the value unencoded - special characters are percent-encoded for you.\n    A button left out of `url_button_data` falls back to the example value\n    registered with the template.",
        "operationId": "send_message_api_v1_messages_send_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIMessageSendRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIMessageSendResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "HTTPBearer": []
          }
        ]
      }
    },
    "/api/v1/messages/send-message": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Send free-form message via API",
        "description": "Send a free-form WhatsApp message (text or media) without using a template.\n\n    **Important:** Free-form messages can only be sent within the 24-hour customer service window\n    (i.e., the contact must have messaged you in the last 24 hours). Outside this window,\n    you must use the template-based `/send` endpoint.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`\n\n    **Supported message types:**\n    - `text` - Plain text message (requires `message` field)\n    - `image` - Image with optional caption (requires `media_url`)\n    - `video` - Video with optional caption (requires `media_url`)\n    - `audio` - Audio message (requires `media_url`)\n    - `document` - Document with optional caption and filename (requires `media_url`)\n\n    **Example - Text message:**\n    ```\n    POST /api/v1/messages/send-message\n    Authorization: Bearer wapl_1234567890abcdef\n    Content-Type: application/json\n\n    {\n        \"contact_phone\": \"+1234567890\",\n        \"contact_name\": \"John Doe\",\n        \"message_type\": \"text\",\n        \"message\": \"Hello! How can I help you today?\"\n    }\n    ```\n\n    **Interactive buttons (optional):**\n    Add a `buttons` object to send up to 3 reply buttons OR a single URL button\n    (never both - they are separate WhatsApp message types). Reply button titles\n    must be unique and 20 characters or fewer. When `buttons` is present the\n    message body is limited to 1024 characters. Interactive messages are session\n    messages, so the 24-hour window must be open.\n\n    Buttons work with `message_type` `text`, `image`, `video`, and `document`.\n    For a media type the media becomes the interactive header (so `media_url` is\n    required) and `message` is the body shown above the buttons - one message,\n    media and buttons together. `audio` is not a valid WhatsApp interactive\n    header type and cannot carry buttons.\n\n    **Example - Reply buttons:**\n    ```\n    {\n        \"contact_phone\": \"+1234567890\",\n        \"message_type\": \"text\",\n        \"message\": \"Did this answer your question?\",\n        \"buttons\": {\n            \"type\": \"reply\",\n            \"reply_buttons\": [\n                {\"id\": \"yes\", \"title\": \"Yes, thanks\"},\n                {\"id\": \"no\", \"title\": \"No, I need help\"}\n            ]\n        }\n    }\n    ```\n\n    **Example - URL button:**\n    ```\n    {\n        \"contact_phone\": \"+1234567890\",\n        \"message_type\": \"text\",\n        \"message\": \"Browse our latest catalog.\",\n        \"buttons\": {\n            \"type\": \"cta_url\",\n            \"url_button\": {\"display_text\": \"View catalog\", \"url\": \"https://example.com\"}\n        }\n    }\n    ```\n\n    **Example - image header + reply buttons:**\n    ```\n    {\n        \"contact_phone\": \"+1234567890\",\n        \"message_type\": \"image\",\n        \"media_url\": \"https://example.com/product.jpg\",\n        \"message\": \"Like this one?\",\n        \"buttons\": {\n            \"type\": \"reply\",\n            \"reply_buttons\": [\n                {\"id\": \"buy\", \"title\": \"Buy now\"},\n                {\"id\": \"more\", \"title\": \"Show me more\"}\n            ]\n        }\n    }\n    ```\n\n    **Catalog / product messages (optional):**\n    Add a `catalog` object instead of `buttons` to send a catalog/product\n    interactive message (mutually exclusive with `buttons`). `catalog_id` and\n    any `product_retailer_id` must belong to a catalog already synced via\n    `/api/catalog/sync`. Like buttons, these are session messages and require\n    an open 24-hour window. See\n    https://developers.facebook.com/documentation/business-messaging/whatsapp/catalogs/catalog-messages\n\n    **Example - browse the connected catalog:**\n    ```\n    {\n        \"contact_phone\": \"+1234567890\",\n        \"message\": \"Check out our latest collection!\",\n        \"catalog\": {\"type\": \"catalog_message\"}\n    }\n    ```\n\n    **Example - single product:**\n    ```\n    {\n        \"contact_phone\": \"+1234567890\",\n        \"message\": \"This one's back in stock.\",\n        \"catalog\": {\n            \"type\": \"product\",\n            \"catalog_id\": \"123456789012345\",\n            \"product_retailer_id\": \"SKU-001\"\n        }\n    }\n    ```\n\n    **Example - multi-product list:**\n    ```\n    {\n        \"contact_phone\": \"+1234567890\",\n        \"message\": \"Here are today's picks.\",\n        \"catalog\": {\n            \"type\": \"product_list\",\n            \"catalog_id\": \"123456789012345\",\n            \"header_text\": \"Today's Picks\",\n            \"sections\": [\n                {\n                    \"title\": \"Best sellers\",\n                    \"product_items\": [\n                        {\"product_retailer_id\": \"SKU-001\"},\n                        {\"product_retailer_id\": \"SKU-002\"}\n                    ]\n                }\n            ]\n        }\n    }\n    ```\n\n    **Replying to a message (optional):**\n    Pass `reply_to_message_id` with the WhatsApp message ID (wamid) of the\n    message you want to reply to. The customer sees that message quoted above\n    your new message. Use the `message_id` returned by send endpoints or the\n    one received in your inbound-message webhooks.\n\n    **Example - Quoted reply:**\n    ```\n    {\n        \"contact_phone\": \"+1234567890\",\n        \"message_type\": \"text\",\n        \"message\": \"Yes, your order has shipped!\",\n        \"reply_to_message_id\": \"wamid.HBgMOTE4ODIyNDMyNDI5FQIAERgS...\"\n    }\n    ```",
        "operationId": "send_free_message_api_v1_messages_send_message_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIFreeMessageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIFreeMessageResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "HTTPBearer": []
          }
        ]
      }
    },
    "/api/v1/messages/typing-indicator": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Show a typing indicator",
        "description": "Show a WhatsApp typing indicator to a contact (and mark their latest\n    inbound message as read). Use this while your system is preparing a reply\n    to make the conversation feel more natural.\n\n    **How it works:**\n    - The message to acknowledge is resolved automatically from the contact's\n      most recent inbound message - you only pass the phone number.\n    - The indicator is dismissed by WhatsApp automatically after about 25\n      seconds, or as soon as you send a message.\n    - Best-effort: if the indicator cannot be shown (e.g., the contact has\n      never messaged you, so there is nothing to acknowledge), the endpoint\n      returns `status: \"skipped\"` instead of an error.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`\n\n    **Example Request:**\n    ```\n    POST /api/v1/messages/typing-indicator\n    Authorization: Bearer wapl_1234567890abcdef\n    Content-Type: application/json\n\n    {\n        \"contact_phone\": \"+1234567890\"\n    }\n    ```",
        "operationId": "send_typing_indicator_api_v1_messages_typing_indicator_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APITypingIndicatorRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APITypingIndicatorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "HTTPBearer": []
          }
        ]
      }
    },
    "/api/v1/templates/": {
      "get": {
        "tags": [
          "Public API v1"
        ],
        "summary": "List all templates",
        "description": "Retrieve all WhatsApp message templates for your account.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`\n\n    **Example Request:**\n    ```\n    GET /api/v1/templates/\n    Authorization: Bearer wapl_1234567890abcdef\n    ```",
        "operationId": "list_templates_api_v1_templates__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APITemplateListResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "HTTPBearer": []
          }
        ]
      }
    },
    "/api/v1/templates/create": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Create a new template",
        "description": "Create a new WhatsApp message template on Meta and store it locally.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`\n\n    **Example Request:**\n    ```json\n    POST /api/v1/templates/create\n    Authorization: Bearer wapl_xxx\n    Content-Type: application/json\n\n    {\n        \"name\": \"order_update\",\n        \"category\": \"UTILITY\",\n        \"language\": \"en_US\",\n        \"waba_phone_id\": \"1234567890\",\n        \"header\": {\n            \"format\": \"TEXT\",\n            \"text\": \"Order Update\"\n        },\n        \"body\": {\n            \"text\": \"Hello {{1}}, your order {{2}} has been shipped!\",\n            \"examples\": {\"1\": \"John\", \"2\": \"ORD-12345\"}\n        },\n        \"footer\": {\n            \"text\": \"Thank you for shopping with us\"\n        },\n        \"buttons\": [\n            {\"type\": \"URL\", \"text\": \"Track Order\", \"url\": \"https://example.com/track/{{1}}\", \"url_example\": \"https://example.com/track/ORD-12345\"}\n        ]\n    }\n    ```\n\n    **Notes:**\n    - Template names must be lowercase, alphanumeric with underscores only\n    - Body is required for MARKETING and UTILITY categories\n    - Media headers (IMAGE, VIDEO, DOCUMENT) are not supported via this endpoint - use the dashboard for media header templates\n    - Templates are submitted to Meta for review and may take up to 24 hours to be approved",
        "operationId": "create_template_api_v1_templates_create_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APICreateTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APICreateTemplateResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "HTTPBearer": []
          }
        ]
      }
    },
    "/api/v1/templates/sync": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Sync templates with Meta",
        "description": "Trigger a full template sync with Meta's WhatsApp Business API.\n    This fetches all templates from Meta, creates missing ones locally,\n    updates changed ones, and removes deleted ones.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`\n\n    **Example Request:**\n    ```\n    POST /api/v1/templates/sync\n    Authorization: Bearer wapl_xxx\n    ```",
        "operationId": "sync_templates_api_v1_templates_sync_post",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        },
        "security": [
          {
            "HTTPBearer": []
          }
        ]
      }
    },
    "/api/v1/templates/create-carousel": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Create a carousel template",
        "description": "Create a media card carousel template on Meta. Category is always MARKETING.\n    Each card requires a `media_url` - we download the media and upload it to Meta.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`\n\n    **Example Request:**\n    ```json\n    POST /api/v1/templates/create-carousel\n    Authorization: Bearer wapl_xxx\n    Content-Type: application/json\n\n    {\n        \"name\": \"product_showcase\",\n        \"language\": \"en_US\",\n        \"waba_phone_id\": \"1234567890\",\n        \"body\": {\n            \"text\": \"Hi {{1}}, check out our top picks!\",\n            \"examples\": {\"1\": \"John\"}\n        },\n        \"cards\": [\n            {\n                \"header_format\": \"IMAGE\",\n                \"media_url\": \"https://example.com/product1.jpg\",\n                \"body_text\": \"Product 1 - Amazing quality.\",\n                \"buttons\": [\n                    {\"type\": \"URL\", \"text\": \"Shop\", \"url\": \"https://example.com/{{1}}\", \"url_example\": \"https://example.com/p1\"},\n                    {\"type\": \"QUICK_REPLY\", \"text\": \"Info\"}\n                ]\n            },\n            {\n                \"header_format\": \"IMAGE\",\n                \"media_url\": \"https://example.com/product2.jpg\",\n                \"body_text\": \"Product 2 - Best seller.\",\n                \"buttons\": [\n                    {\"type\": \"URL\", \"text\": \"Shop\", \"url\": \"https://example.com/{{1}}\", \"url_example\": \"https://example.com/p2\"},\n                    {\"type\": \"QUICK_REPLY\", \"text\": \"Info\"}\n                ]\n            }\n        ]\n    }\n    ```\n\n    **Notes:**\n    - Carousel templates are always MARKETING category\n    - 2-10 cards required, all cards must have the same header format, button structure, and body presence\n    - Each card needs a public `media_url` (IMAGE: jpg/png, VIDEO: mp4)",
        "operationId": "create_carousel_template_api_v1_templates_create_carousel_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APICreateCarouselTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APICreateTemplateResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "HTTPBearer": []
          }
        ]
      }
    },
    "/api/v1/contacts/": {
      "get": {
        "tags": [
          "Public API v1"
        ],
        "summary": "List contacts",
        "description": "Retrieve a paginated list of contacts for your account.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "list_contacts_api_v1_contacts__get",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "description": "Page number",
              "default": 1,
              "title": "Page"
            },
            "description": "Page number"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Items per page",
              "default": 20,
              "title": "Limit"
            },
            "description": "Items per page"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 100
                },
                {
                  "type": "null"
                }
              ],
              "description": "Search by name, phone, or email",
              "title": "Search"
            },
            "description": "Search by name, phone, or email"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIContactListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Create a contact",
        "description": "Create a new contact in your account.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "create_contact_api_v1_contacts__post",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIContactCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIContactResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/{contact_id}": {
      "get": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Get a contact",
        "description": "Retrieve a single contact by ID.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "get_contact_api_v1_contacts__contact_id__get",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "contact_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Contact Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIContactResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Update a contact",
        "description": "Update an existing contact by ID.\n\n    Only the fields you send are changed. Omit a field (or send `null`) to leave it\n    unchanged; send an empty string to clear a text field. `tags` and `custom_fields`\n    replace their existing values entirely rather than merging.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "update_contact_api_v1_contacts__contact_id__put",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "contact_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Contact Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIContactUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIContactResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Delete a contact",
        "description": "Delete a contact by ID (soft delete).\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "delete_contact_api_v1_contacts__contact_id__delete",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "contact_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Contact Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIContactDeleteResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/phone/{phone_number}": {
      "get": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Get a contact by phone number",
        "description": "Retrieve a single contact by phone number.\n\n    The phone number must include the country code and be 8-15 digits\n    (e.g. `919066666666`). A leading `+` is accepted and stripped.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "get_contact_by_phone_api_v1_contacts_phone__phone_number__get",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "phone_number",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Phone Number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIContactResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Update a contact by phone number",
        "description": "Update an existing contact by phone number.\n\n    The phone number must include the country code and be 8-15 digits\n    (e.g. `919066666666`). Only the fields you send are changed. Omit a\n    field (or send `null`) to leave it unchanged; send an empty string to\n    clear a text field. `tags` and `custom_fields` replace their existing\n    values entirely rather than merging.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "update_contact_by_phone_api_v1_contacts_phone__phone_number__put",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "phone_number",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Phone Number"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIContactUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIContactResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Delete a contact by phone number",
        "description": "Delete a contact by phone number (soft delete).\n\n    The phone number must include the country code and be 8-15 digits\n    (e.g. `919066666666`).\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "delete_contact_by_phone_api_v1_contacts_phone__phone_number__delete",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "phone_number",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Phone Number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIPhoneContactDeleteResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/groups/": {
      "get": {
        "tags": [
          "Public API v1"
        ],
        "summary": "List contact groups",
        "description": "Retrieve a paginated list of contact groups for your account.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "list_groups_api_v1_groups__get",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "description": "Page number",
              "default": 1,
              "title": "Page"
            },
            "description": "Page number"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Items per page",
              "default": 20,
              "title": "Limit"
            },
            "description": "Items per page"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 100
                },
                {
                  "type": "null"
                }
              ],
              "description": "Search by group name or description",
              "title": "Search"
            },
            "description": "Search by group name or description"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIGroupListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Create a contact group",
        "description": "Create a new contact group. Optionally include contact IDs to add to the group.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "create_group_api_v1_groups__post",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIGroupCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIGroupResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/groups/{group_id}": {
      "get": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Get a contact group",
        "description": "Retrieve a single contact group by ID.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "get_group_api_v1_groups__group_id__get",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Group Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIGroupResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Delete a contact group",
        "description": "Delete a contact group by ID (soft delete). Contacts in the group are not deleted.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "delete_group_api_v1_groups__group_id__delete",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Group Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIGroupDeleteResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/groups/{group_id}/contacts": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Add contacts to a group",
        "description": "Add one or more contacts to a contact group by their IDs.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "add_contacts_to_group_api_v1_groups__group_id__contacts_post",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Group Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIGroupContactsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIGroupContactsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Remove contacts from a group",
        "description": "Remove one or more contacts from a contact group. The contacts themselves are not deleted.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "remove_contacts_from_group_api_v1_groups__group_id__contacts_delete",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Group Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIGroupContactsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIGroupContactsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/groups/{group_id}/contacts/phone": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Add contacts to a group by phone number",
        "description": "Add one or more contacts to a contact group by their phone numbers.\n\n    Each phone number must include the country code and be 8-15 digits\n    (e.g. `919066666666`).\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "add_contacts_to_group_by_phone_api_v1_groups__group_id__contacts_phone_post",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Group Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIGroupContactsPhoneRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIGroupContactsPhoneResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Remove contacts from a group by phone number",
        "description": "Remove one or more contacts from a contact group by their phone numbers.\n    The contacts themselves are not deleted.\n\n    Each phone number must include the country code and be 8-15 digits\n    (e.g. `919066666666`).\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "remove_contacts_from_group_by_phone_api_v1_groups__group_id__contacts_phone_delete",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Group Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIGroupContactsPhoneRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIGroupContactsPhoneResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/campaigns/": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Create a campaign",
        "description": "Create a WhatsApp campaign from a list of phone numbers using an approved template.\n\n    **Authentication:** `Authorization: Bearer wapl_xxx`\n\n    Phone numbers are normalized and upserted as contacts in your account.\n    If the template has a media header (IMAGE / VIDEO / DOCUMENT), pass a\n    publicly accessible `media_url` - it will be fetched and uploaded to Meta\n    before sending.\n\n    Carousel templates and per-contact variable overrides are not yet\n    supported via this endpoint.",
        "operationId": "create_campaign_api_v1_campaigns__post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APICampaignCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APICampaignCreateResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "HTTPBearer": []
          }
        ]
      }
    },
    "/api/v1/campaigns/{campaign_id}/send": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Send a campaign",
        "description": "Run prechecks and enqueue the campaign for sending via the background worker.",
        "operationId": "send_campaign_api_v1_campaigns__campaign_id__send_post",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Campaign Id"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APICampaignSendResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/campaigns/{campaign_id}/stats": {
      "get": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Get campaign stats",
        "description": "Return aggregate per-contact delivery stats for a campaign.",
        "operationId": "get_campaign_stats_api_v1_campaigns__campaign_id__stats_get",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Campaign Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APICampaignStatsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/agents/": {
      "get": {
        "tags": [
          "Public API v1"
        ],
        "summary": "List agents",
        "description": "Retrieve the agents (team members) in your organisation. Use the returned\n    `user_id` values when assigning a conversation to an agent.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`\n\n    **Filtering:**\n    - `role` - owner, admin, manager, or agent\n    - `status` - active (default) or deactivated\n    - `search` - case-insensitive match on name or email",
        "operationId": "list_agents_api_v1_agents__get",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "description": "Page number",
              "default": 1,
              "title": "Page"
            },
            "description": "Page number"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Items per page",
              "default": 50,
              "title": "Limit"
            },
            "description": "Items per page"
          },
          {
            "name": "role",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by role: owner, admin, manager, or agent",
              "title": "Role"
            },
            "description": "Filter by role: owner, admin, manager, or agent"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Filter by membership status: active or deactivated",
              "default": "active",
              "title": "Status"
            },
            "description": "Filter by membership status: active or deactivated"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 100
                },
                {
                  "type": "null"
                }
              ],
              "description": "Search by name or email",
              "title": "Search"
            },
            "description": "Search by name or email"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIAgentListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/conversations/{contact_phone}/assign": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Assign a conversation to an agent",
        "description": "Assign (or reassign) the conversation for a contact phone to an agent.\n\n    - `contact_phone` is matched digits-only (no leading `+`), e.g. `12125551234`.\n    - Behaves exactly like the inbox UI: emits real-time updates, records the\n      transfer in history, and writes an audit entry.\n    - `404` if `user_id` is not an active member of your organisation.\n    - `400` if the conversation is resolved - reopen it first.",
        "operationId": "assign_conversation_api_v1_conversations__contact_phone__assign_post",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "contact_phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Contact Phone"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIAssignConversationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIAssignmentResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/conversations/{contact_phone}/unassign": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Unassign a conversation",
        "description": "Release the conversation back to the unassigned pool. Idempotent - if the\n    conversation is already unassigned this returns `200` with `no_op` semantics.",
        "operationId": "unassign_conversation_api_v1_conversations__contact_phone__unassign_post",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "contact_phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Contact Phone"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIConversationWabaRequest",
                "default": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIAssignmentResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/conversations/{contact_phone}/reopen": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Reopen a resolved conversation",
        "description": "Reopen a resolved conversation so it can be worked / assigned again. The\n    reopener (your API key's account) becomes the assignee, matching the inbox\n    behaviour. Idempotent - reopening an already-open conversation is a no-op.",
        "operationId": "reopen_conversation_api_v1_conversations__contact_phone__reopen_post",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "contact_phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Contact Phone"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/APIConversationWabaRequest",
                "default": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIAssignmentResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/conversations/{contact_phone}/assignment": {
      "get": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Get a conversation's assignment state",
        "description": "Read the current assignee and status for a contact's conversation\n    (read-before-write for integrations). `has_conversation` is `false` when no\n    inbox conversation exists yet for this contact - e.g. a lead created via the\n    API that has never messaged.",
        "operationId": "get_assignment_state_api_v1_conversations__contact_phone__assignment_get",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "contact_phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Contact Phone"
            }
          },
          {
            "name": "waba_phone_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Optional WABA disambiguation for multi-WABA orgs",
              "title": "Waba Phone Id"
            },
            "description": "Optional WABA disambiguation for multi-WABA orgs"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIAssignmentStateResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/flows/{flow_id}/trigger": {
      "post": {
        "tags": [
          "Public API v1"
        ],
        "summary": "Trigger a chatbot flow for a contact",
        "description": "Start a Flows V2 chatbot flow on a contact from an external system.\n\n    The flow must be **active** and have a **Webhook** trigger on its Start step.\n\n    The body is accepted in **any shape**. The simplest is `{\"phone\": \"...\",\n    \"variables\": {...}}`, but you may also POST your CRM's own raw payload: the\n    contact's phone is read via the trigger's **Phone field** path (default\n    `phone`), and the whole body is exposed to the flow verbatim as\n    `{{webhook.*}}` (e.g. `{{webhook.contact.mobile}}`) - no per-field mapping.\n\n    The body is read tolerantly: JSON (object **or** top-level array, even when the\n    sender mis-sets `Content-Type`) and `application/x-www-form-urlencoded` are all\n    accepted, so practically any webhook source works.\n\n    **Authentication:**\n    - Pass your API key in the `Authorization` header: `Authorization: Bearer wapl_xxx`",
        "operationId": "trigger_flow_api_v1_flows__flow_id__trigger_post",
        "security": [
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "flow_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Flow Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIFlowTriggerResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "phone": "+1234567890",
                "variables": {
                  "name": "John",
                  "status": "approved"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "APIAgentItem": {
        "properties": {
          "user_id": {
            "type": "string",
            "title": "User Id",
            "description": "Agent user ID - pass this as `user_id` when assigning a conversation",
            "example": "665f1c2e8a1b2c3d4e5f6a7b"
          },
          "full_name": {
            "type": "string",
            "title": "Full Name",
            "description": "Agent display name",
            "example": "Priya Sharma"
          },
          "email": {
            "type": "string",
            "title": "Email",
            "description": "Agent email address",
            "example": "priya@acme.com"
          },
          "role": {
            "type": "string",
            "title": "Role",
            "description": "Org role: owner, admin, manager, or agent",
            "example": "agent"
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Membership status: active or deactivated",
            "example": "active"
          }
        },
        "type": "object",
        "required": [
          "user_id",
          "full_name",
          "email",
          "role",
          "status"
        ],
        "title": "APIAgentItem",
        "description": "A single assignable agent / team member in the organisation."
      },
      "APIAgentListResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "agents": {
            "items": {
              "$ref": "#/components/schemas/APIAgentItem"
            },
            "type": "array",
            "title": "Agents",
            "description": "List of agents in your organisation"
          },
          "total": {
            "type": "integer",
            "title": "Total",
            "description": "Total number of agents matching the filter"
          },
          "page": {
            "type": "integer",
            "title": "Page",
            "description": "Current page"
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "Page size"
          }
        },
        "type": "object",
        "required": [
          "status",
          "agents",
          "total",
          "page",
          "limit"
        ],
        "title": "APIAgentListResponse",
        "description": "Schema for paginated agent list response."
      },
      "APIAssignConversationRequest": {
        "properties": {
          "user_id": {
            "type": "string",
            "title": "User Id",
            "description": "user_id of the agent to assign the conversation to (from GET /agents)",
            "example": "665f1c2e8a1b2c3d4e5f6a7b"
          },
          "note": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "title": "Note",
            "description": "Optional handoff note - recorded on the transfer history when reassigning"
          },
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "Optional WABA disambiguation when the same contact phone exists under multiple WABAs"
          }
        },
        "type": "object",
        "required": [
          "user_id"
        ],
        "title": "APIAssignConversationRequest",
        "description": "Body for assigning / reassigning a conversation to an agent."
      },
      "APIAssignmentData": {
        "properties": {
          "phone_number": {
            "type": "string",
            "title": "Phone Number",
            "description": "Normalised contact phone (digits only, no '+')"
          },
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "WABA phone ID the conversation belongs to"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status",
            "description": "Conversation status: open or resolved"
          },
          "assigned_to": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Assigned To",
            "description": "user_id of the current assignee (null if unassigned)"
          },
          "assigned_to_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Assigned To Name",
            "description": "Display name of the current assignee"
          },
          "assigned_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Assigned At",
            "description": "ISO-8601 timestamp of the assignment"
          },
          "is_reassignment": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Reassignment",
            "description": "True when this assignment replaced a previous assignee"
          },
          "previous_assignee_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Previous Assignee Id",
            "description": "user_id of the previous assignee, if any"
          },
          "previous_assignee_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Previous Assignee Name",
            "description": "Display name of the previous assignee"
          },
          "note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Note",
            "description": "Handoff note recorded with the assignment"
          },
          "no_op": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "No Op",
            "description": "True when the call made no change (already in this state)"
          }
        },
        "type": "object",
        "required": [
          "phone_number"
        ],
        "title": "APIAssignmentData",
        "description": "Assignment state echoed back after an assign / unassign / reopen call."
      },
      "APIAssignmentResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Human-readable result message"
          },
          "data": {
            "$ref": "#/components/schemas/APIAssignmentData"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "data"
        ],
        "title": "APIAssignmentResponse",
        "description": "Response for assign / unassign / reopen."
      },
      "APIAssignmentStateData": {
        "properties": {
          "phone_number": {
            "type": "string",
            "title": "Phone Number",
            "description": "Normalised contact phone (digits only, no '+')"
          },
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "WABA phone ID resolved for this contact"
          },
          "has_conversation": {
            "type": "boolean",
            "title": "Has Conversation",
            "description": "False when no inbox conversation exists yet for this contact (e.g. a lead that never messaged)"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status",
            "description": "Conversation status: open or resolved"
          },
          "assigned_to": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Assigned To",
            "description": "user_id of the current assignee (null if unassigned)"
          },
          "assigned_to_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Assigned To Name",
            "description": "Display name of the current assignee"
          },
          "assigned_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Assigned At",
            "description": "ISO-8601 timestamp of the assignment"
          }
        },
        "type": "object",
        "required": [
          "phone_number",
          "has_conversation"
        ],
        "title": "APIAssignmentStateData",
        "description": "Current assignment + status snapshot for a contact's conversation."
      },
      "APIAssignmentStateResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "data": {
            "$ref": "#/components/schemas/APIAssignmentStateData"
          }
        },
        "type": "object",
        "required": [
          "status",
          "data"
        ],
        "title": "APIAssignmentStateResponse",
        "description": "Response for the read-only assignment-state endpoint."
      },
      "APICampaignContactInput": {
        "properties": {
          "phone": {
            "type": "string",
            "maxLength": 15,
            "minLength": 8,
            "title": "Phone",
            "description": "Phone number with country code (e.g., +1234567890)",
            "example": "+1234567890"
          },
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Contact name (used only when creating a new contact)",
            "example": "John Doe"
          }
        },
        "type": "object",
        "required": [
          "phone"
        ],
        "title": "APICampaignContactInput",
        "description": "Single contact entry for a campaign payload"
      },
      "APICampaignCreateRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Name",
            "description": "Campaign name",
            "example": "Summer Sale"
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1000
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Campaign description"
          },
          "template_name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Template Name",
            "description": "Approved template name"
          },
          "contacts": {
            "items": {
              "$ref": "#/components/schemas/APICampaignContactInput"
            },
            "type": "array",
            "maxItems": 10000,
            "minItems": 1,
            "title": "Contacts",
            "description": "Recipient contacts (phones + optional names). Up to 10,000 per request."
          },
          "body_data": {
            "additionalProperties": true,
            "type": "object",
            "title": "Body Data",
            "description": "Body template variables applied to every contact. Same format as /messages/send (e.g. {\"1\":\"value\"})."
          },
          "header_data": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Header Data",
            "description": "Header variables (for TEXT headers). Use {\"1\": \"value\"} style keys."
          },
          "media_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Media Url",
            "description": "Public URL to media (required if template has IMAGE/VIDEO/DOCUMENT header)"
          },
          "filename": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Filename",
            "description": "Filename (for DOCUMENT media)"
          },
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "WABA phone ID to use. Falls back to template's, then user's first."
          },
          "scheduled_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Scheduled At",
            "description": "Scheduled send time (ISO 8601). If omitted, campaign is created as draft."
          },
          "scheduled_timezone": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ],
            "title": "Scheduled Timezone",
            "description": "IANA timezone string (e.g. Asia/Kolkata)"
          },
          "expiration_time_ms": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiration Time Ms",
            "description": "Expiration time in milliseconds for limited-time offer templates"
          },
          "carousel_data": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Carousel Data",
            "description": "Per-card data for carousel templates. One entry per card. Each entry may include: media_url (public image/video URL, required if card media not stored on template), body_data (dict of card body variables, e.g. {\"1\": \"value\"}), button_payloads (list of QUICK_REPLY payloads in button order), url_button_params (list of URL-button {{1}} substitutions in button order). If omitted for a carousel template, each card uses the template's stored media_url and example button values."
          },
          "catalog_product_retailer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Catalog Product Retailer Id",
            "description": "Thumbnail product for a CATALOG-button template. Optional - when omitted, any product synced for the catalog attached to the sending number is used."
          },
          "mpm_sections": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mpm Sections",
            "description": "Product sections for an MPM (multi-product) template. Required for one - there is no safe default. Max 10 sections / 30 products: [{\"title\": \"Popular\", \"product_items\": [{\"product_retailer_id\": \"sku_1\"}]}]"
          },
          "spm_product": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Spm Product",
            "description": "The product for an SPM (single-product) template. Required for one: {\"catalog_id\": \"123\", \"product_retailer_id\": \"sku_1\"}"
          }
        },
        "type": "object",
        "required": [
          "name",
          "template_name",
          "contacts"
        ],
        "title": "APICampaignCreateRequest",
        "description": "Schema for creating a campaign via public API"
      },
      "APICampaignCreateResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message"
          },
          "campaign_id": {
            "type": "string",
            "title": "Campaign Id",
            "description": "Created campaign ID"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Campaign name"
          },
          "status_value": {
            "type": "string",
            "title": "Status Value",
            "description": "Campaign status: 'draft' or 'scheduled'"
          },
          "total_contacts": {
            "type": "integer",
            "title": "Total Contacts",
            "description": "Number of contacts targeted"
          },
          "invalid_phones": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Invalid Phones",
            "description": "Phone numbers that failed normalization and were skipped"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "Response timestamp"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "campaign_id",
          "name",
          "status_value",
          "total_contacts",
          "timestamp"
        ],
        "title": "APICampaignCreateResponse",
        "description": "Schema for campaign create response"
      },
      "APICampaignSendResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "accepted"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message"
          },
          "campaign_id": {
            "type": "string",
            "title": "Campaign Id",
            "description": "Campaign ID"
          },
          "task_id": {
            "type": "string",
            "title": "Task Id",
            "description": "Celery task ID for tracking"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "Response timestamp"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "campaign_id",
          "task_id",
          "timestamp"
        ],
        "title": "APICampaignSendResponse",
        "description": "Schema for campaign send response"
      },
      "APICampaignStatsResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "campaign_id": {
            "type": "string",
            "title": "Campaign Id",
            "description": "Campaign ID"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Campaign name"
          },
          "campaign_status": {
            "type": "string",
            "title": "Campaign Status",
            "description": "Campaign lifecycle status"
          },
          "total_contacts": {
            "type": "integer",
            "title": "Total Contacts",
            "description": "Total contacts targeted",
            "default": 0
          },
          "sent_count": {
            "type": "integer",
            "title": "Sent Count",
            "description": "Number of contacts the message was sent to",
            "default": 0
          },
          "delivered_count": {
            "type": "integer",
            "title": "Delivered Count",
            "description": "Number of contacts who received the message",
            "default": 0
          },
          "read_count": {
            "type": "integer",
            "title": "Read Count",
            "description": "Number of contacts who read the message",
            "default": 0
          },
          "clicked_count": {
            "type": "integer",
            "title": "Clicked Count",
            "description": "Number of contacts who clicked a CTA",
            "default": 0
          },
          "failed_count": {
            "type": "integer",
            "title": "Failed Count",
            "description": "Number of contacts for whom sending failed",
            "default": 0
          },
          "replied_count": {
            "type": "integer",
            "title": "Replied Count",
            "description": "Number of contacts who replied",
            "default": 0
          },
          "success_count": {
            "type": "integer",
            "title": "Success Count",
            "description": "total_contacts - failed_count",
            "default": 0
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At",
            "description": "Campaign creation time"
          },
          "scheduled_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Scheduled At",
            "description": "Scheduled send time"
          },
          "started_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Started At",
            "description": "Actual send start time"
          },
          "completed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completed At",
            "description": "Campaign completion time"
          }
        },
        "type": "object",
        "required": [
          "status",
          "campaign_id",
          "name",
          "campaign_status"
        ],
        "title": "APICampaignStatsResponse",
        "description": "Schema for campaign stats response"
      },
      "APICarouselCardButtonRequest": {
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "QUICK_REPLY",
              "URL",
              "PHONE_NUMBER",
              "COPY_CODE",
              "FLOW"
            ],
            "title": "Type",
            "description": "Button type"
          },
          "text": {
            "type": "string",
            "maxLength": 25,
            "title": "Text",
            "description": "Button label text"
          },
          "url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url",
            "description": "URL for URL buttons (supports {{1}} suffix)"
          },
          "url_example": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url Example",
            "description": "Example value for URL variable"
          },
          "phone_number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone Number",
            "description": "Phone number for PHONE_NUMBER buttons"
          },
          "copy_code_example": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Copy Code Example",
            "description": "Example coupon code"
          },
          "flow_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flow Id",
            "description": "Flow ID for FLOW buttons"
          },
          "flow_action": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flow Action",
            "description": "Flow action",
            "default": "navigate"
          },
          "navigate_screen": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Navigate Screen",
            "description": "Target screen for FLOW buttons"
          }
        },
        "type": "object",
        "required": [
          "type",
          "text"
        ],
        "title": "APICarouselCardButtonRequest",
        "description": "Button within a carousel card (max 2 per card)"
      },
      "APICarouselCardRequest": {
        "properties": {
          "header_format": {
            "type": "string",
            "enum": [
              "IMAGE",
              "VIDEO"
            ],
            "title": "Header Format",
            "description": "Card header media type: IMAGE or VIDEO"
          },
          "media_url": {
            "type": "string",
            "title": "Media Url",
            "description": "Public URL for the card media (image or video). Downloaded and uploaded to Meta."
          },
          "body_text": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 160
              },
              {
                "type": "null"
              }
            ],
            "title": "Body Text",
            "description": "Optional card body text (max 160 chars). If any card has body, all must."
          },
          "buttons": {
            "items": {
              "$ref": "#/components/schemas/APICarouselCardButtonRequest"
            },
            "type": "array",
            "maxItems": 2,
            "minItems": 1,
            "title": "Buttons",
            "description": "1-2 buttons per card"
          }
        },
        "type": "object",
        "required": [
          "header_format",
          "media_url",
          "buttons"
        ],
        "title": "APICarouselCardRequest",
        "description": "Single card in a media carousel template"
      },
      "APIContactCreateRequest": {
        "properties": {
          "phone_number": {
            "type": "string",
            "maxLength": 15,
            "minLength": 8,
            "title": "Phone Number",
            "description": "Phone number with country code (e.g., +1234567890)"
          },
          "first_name": {
            "type": "string",
            "maxLength": 100,
            "minLength": 1,
            "title": "First Name",
            "description": "Contact first name"
          },
          "last_name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Name",
            "description": "Contact last name"
          },
          "email": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Email address"
          },
          "company": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ],
            "title": "Company",
            "description": "Company name"
          },
          "website": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ],
            "title": "Website",
            "description": "Website URL"
          },
          "industry": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ],
            "title": "Industry",
            "description": "Industry"
          },
          "address": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ],
            "title": "Address",
            "description": "Address"
          },
          "tags": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tags",
            "description": "Tags for the contact"
          },
          "custom_fields": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom Fields",
            "description": "Custom field values keyed by field key, e.g. {\"location\": \"Mumbai\"}. Unknown keys are ignored; values are validated against the org's custom-field definitions."
          }
        },
        "type": "object",
        "required": [
          "phone_number",
          "first_name"
        ],
        "title": "APIContactCreateRequest",
        "description": "Schema for creating a contact via public API"
      },
      "APIContactDeleteResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message"
          },
          "contact_id": {
            "type": "string",
            "title": "Contact Id",
            "description": "Deleted contact ID"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "contact_id"
        ],
        "title": "APIContactDeleteResponse",
        "description": "Schema for contact deletion response"
      },
      "APIContactItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Contact ID"
          },
          "first_name": {
            "type": "string",
            "title": "First Name",
            "description": "First name"
          },
          "last_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Name",
            "description": "Last name"
          },
          "phone_number": {
            "type": "string",
            "title": "Phone Number",
            "description": "Phone number"
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Email address"
          },
          "company": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Company",
            "description": "Company name"
          },
          "website": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Website",
            "description": "Website URL"
          },
          "industry": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Industry",
            "description": "Industry"
          },
          "address": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Address",
            "description": "Address"
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Tags",
            "description": "Contact tags"
          },
          "opted_in": {
            "type": "boolean",
            "title": "Opted In",
            "description": "Opt-in status",
            "default": true
          },
          "source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source",
            "description": "Contact source"
          },
          "custom_fields": {
            "additionalProperties": true,
            "type": "object",
            "title": "Custom Fields",
            "description": "Custom field values"
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At",
            "description": "Creation timestamp"
          }
        },
        "type": "object",
        "required": [
          "id",
          "first_name",
          "phone_number"
        ],
        "title": "APIContactItem",
        "description": "Schema for a single contact in API responses"
      },
      "APIContactListResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "contacts": {
            "items": {
              "$ref": "#/components/schemas/APIContactItem"
            },
            "type": "array",
            "title": "Contacts",
            "description": "List of contacts"
          },
          "total": {
            "type": "integer",
            "title": "Total",
            "description": "Total number of contacts"
          },
          "page": {
            "type": "integer",
            "title": "Page",
            "description": "Current page"
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "Page size"
          }
        },
        "type": "object",
        "required": [
          "status",
          "contacts",
          "total",
          "page",
          "limit"
        ],
        "title": "APIContactListResponse",
        "description": "Schema for paginated contact list response"
      },
      "APIContactResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message"
          },
          "contact": {
            "$ref": "#/components/schemas/APIContactItem",
            "description": "Contact data"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "contact"
        ],
        "title": "APIContactResponse",
        "description": "Schema for single contact operation responses"
      },
      "APIContactUpdateRequest": {
        "properties": {
          "phone_number": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 15,
                "minLength": 8
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone Number",
            "description": "Phone number with country code (e.g., +1234567890). Must not belong to another contact"
          },
          "first_name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "First Name",
            "description": "Contact first name"
          },
          "last_name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Name",
            "description": "Contact last name"
          },
          "email": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Email address"
          },
          "company": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ],
            "title": "Company",
            "description": "Company name"
          },
          "website": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ],
            "title": "Website",
            "description": "Website URL"
          },
          "industry": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ],
            "title": "Industry",
            "description": "Industry"
          },
          "address": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ],
            "title": "Address",
            "description": "Address"
          },
          "tags": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tags",
            "description": "Tags for the contact. Replaces the existing tags entirely"
          },
          "opted_in": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Opted In",
            "description": "Opt-in status"
          },
          "custom_fields": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom Fields",
            "description": "Custom field values keyed by field key, e.g. {\"location\": \"Mumbai\"}. Replaces the existing custom fields entirely. Unknown keys are ignored; values are validated against the org's custom-field definitions."
          }
        },
        "type": "object",
        "title": "APIContactUpdateRequest",
        "description": "Schema for updating a contact via public API"
      },
      "APIConversationWabaRequest": {
        "properties": {
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "Optional WABA disambiguation for multi-WABA organisations"
          }
        },
        "type": "object",
        "title": "APIConversationWabaRequest",
        "description": "Body for unassign / reopen - only the optional WABA disambiguator."
      },
      "APICreateCarouselTemplateRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 512,
            "minLength": 1,
            "title": "Name",
            "description": "Template name (lowercase, alphanumeric, underscores only)"
          },
          "language": {
            "type": "string",
            "title": "Language",
            "description": "BCP-47 language code",
            "default": "en_US"
          },
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "WABA phone ID to create the template under. If omitted, uses the first WhatsApp number linked to your account."
          },
          "body": {
            "$ref": "#/components/schemas/APITemplateBodyRequest",
            "description": "Top-level message body text (max 1024 chars)"
          },
          "cards": {
            "items": {
              "$ref": "#/components/schemas/APICarouselCardRequest"
            },
            "type": "array",
            "maxItems": 10,
            "minItems": 2,
            "title": "Cards",
            "description": "2-10 media cards for the carousel. Each card requires a media_url."
          },
          "message_send_ttl_seconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message Send Ttl Seconds",
            "description": "Time-to-live for messages sent using this template"
          }
        },
        "type": "object",
        "required": [
          "name",
          "body",
          "cards"
        ],
        "title": "APICreateCarouselTemplateRequest",
        "description": "Schema for creating a media carousel template via public API. Category is always MARKETING."
      },
      "APICreateTemplateRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 512,
            "minLength": 1,
            "title": "Name",
            "description": "Template name (lowercase, alphanumeric, underscores only)"
          },
          "category": {
            "type": "string",
            "enum": [
              "MARKETING",
              "UTILITY",
              "AUTHENTICATION"
            ],
            "title": "Category",
            "description": "Template category"
          },
          "language": {
            "type": "string",
            "title": "Language",
            "description": "BCP-47 language code",
            "default": "en_US"
          },
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "WABA phone ID to create the template under. If omitted, uses the first WhatsApp number linked to your account."
          },
          "header": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/APITemplateHeaderRequest"
              },
              {
                "type": "null"
              }
            ],
            "description": "Header component"
          },
          "media_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Media Url",
            "description": "Public URL for media header (IMAGE/VIDEO/DOCUMENT). We download and upload it to Meta on your behalf."
          },
          "body": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/APITemplateBodyRequest"
              },
              {
                "type": "null"
              }
            ],
            "description": "Body component"
          },
          "footer": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/APITemplateFooterRequest"
              },
              {
                "type": "null"
              }
            ],
            "description": "Footer component"
          },
          "buttons": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/APITemplateButtonRequest"
                },
                "type": "array",
                "maxItems": 10
              },
              {
                "type": "null"
              }
            ],
            "title": "Buttons",
            "description": "Interactive buttons (max 10)"
          },
          "limited_time_offer": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/APITemplateLTORequest"
              },
              {
                "type": "null"
              }
            ],
            "description": "Limited-time offer component (MARKETING only)"
          },
          "offer_code": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 15
              },
              {
                "type": "null"
              }
            ],
            "title": "Offer Code",
            "description": "Offer/coupon code for LTO templates"
          },
          "add_security_recommendation": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Add Security Recommendation",
            "description": "Include security text in auth template body"
          },
          "code_expiration_minutes": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 90,
                "minimum": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Code Expiration Minutes",
            "description": "Code expiry minutes (1-90) for auth templates"
          },
          "message_send_ttl_seconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message Send Ttl Seconds",
            "description": "Time-to-live for messages sent using this template"
          }
        },
        "type": "object",
        "required": [
          "name",
          "category"
        ],
        "title": "APICreateTemplateRequest",
        "description": "Schema for creating a WhatsApp message template via public API"
      },
      "APICreateTemplateResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status: 'success' or 'error'",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message",
            "example": "Template 'order_update' created and submitted for review"
          },
          "template_id": {
            "type": "string",
            "title": "Template Id",
            "description": "Local template ID",
            "example": "507f1f77bcf86cd799439012"
          },
          "meta_template_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Meta Template Id",
            "description": "Meta template ID"
          },
          "meta_status": {
            "type": "string",
            "title": "Meta Status",
            "description": "Meta approval status",
            "default": "PENDING",
            "example": "PENDING"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "template_id"
        ],
        "title": "APICreateTemplateResponse",
        "description": "Schema for create template response"
      },
      "APIFlowTriggerResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status: 'success' or 'error'",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Human-readable result",
            "example": "Flow started"
          },
          "started": {
            "type": "boolean",
            "title": "Started",
            "description": "Whether a flow run was started (or absorbed into an existing live session)"
          },
          "flow_id": {
            "type": "string",
            "title": "Flow Id",
            "description": "The flow that was triggered"
          },
          "session_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Session Id",
            "description": "The flow session ID, when a run was started"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "Response timestamp"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "started",
          "flow_id",
          "timestamp"
        ],
        "title": "APIFlowTriggerResponse",
        "description": "Response for a webhook flow-trigger call."
      },
      "APIFreeMessageRequest": {
        "properties": {
          "contact_phone": {
            "type": "string",
            "maxLength": 15,
            "minLength": 8,
            "title": "Contact Phone",
            "description": "Destination phone number with country code (e.g., +1234567890)",
            "example": "+1234567890"
          },
          "contact_name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Contact Name",
            "description": "Name of the contact. Only used when creating a new (unsaved) contact. If omitted, defaults to 'User #<6-digit number>'",
            "example": "John Doe"
          },
          "message_type": {
            "type": "string",
            "enum": [
              "text",
              "image",
              "video",
              "audio",
              "document"
            ],
            "title": "Message Type",
            "description": "Type of message to send",
            "default": "text",
            "example": "text"
          },
          "message": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4096
              },
              {
                "type": "null"
              }
            ],
            "title": "Message",
            "description": "Text message body (required for message_type='text')",
            "example": "Hello! This is a free-form message."
          },
          "media_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Media Url",
            "description": "Publicly accessible URL for media (required for image/video/audio/document types)",
            "example": "https://example.com/image.jpg"
          },
          "caption": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1024
              },
              {
                "type": "null"
              }
            ],
            "title": "Caption",
            "description": "Caption for media messages (supported for image, video, document)",
            "example": "Check out this image"
          },
          "filename": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Filename",
            "description": "Filename for document messages",
            "example": "report.pdf"
          },
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "WhatsApp Business Account phone ID to use. If not provided, uses user's first phone ID",
            "example": "123456789012345"
          },
          "buttons": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/QuickResponseButtonsSchema"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional interactive buttons: up to 3 reply buttons OR a single URL button (never both). Supported with message_type 'text', 'image', 'video', or 'document' -- for a media type the media becomes the interactive header and `media_url` is required. Audio is not a valid interactive header type, so it cannot carry buttons. When present, the message body is limited to 1024 characters."
          },
          "reply_to_message_id": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 512
              },
              {
                "type": "null"
              }
            ],
            "title": "Reply To Message Id",
            "description": "Optional WhatsApp message ID (wamid) of a message to reply to. When set, the customer sees this message quoted above your new message. Use the message_id returned by send endpoints or received in webhooks.",
            "example": "wamid.HBgMOTE4ODIyNDMyNDI5FQIAERgS..."
          },
          "catalog": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CatalogMessageSchema"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send a catalog/product/product_list interactive message instead of a text/media message. Mutually exclusive with `buttons`. `message` (if provided) is used as the body text. See https://developers.facebook.com/documentation/business-messaging/whatsapp/catalogs/catalog-messages"
          }
        },
        "type": "object",
        "required": [
          "contact_phone"
        ],
        "title": "APIFreeMessageRequest",
        "description": "Schema for sending free-form (non-template) messages via public API"
      },
      "APIFreeMessageResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status: 'success' or 'error'",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message",
            "example": "Message sent successfully"
          },
          "message_id": {
            "type": "string",
            "title": "Message Id",
            "description": "WhatsApp message ID",
            "example": "wamid.xxx"
          },
          "contact_id": {
            "type": "string",
            "title": "Contact Id",
            "description": "Contact ID (created or existing)",
            "example": "507f1f77bcf86cd799439012"
          },
          "message_type": {
            "type": "string",
            "title": "Message Type",
            "description": "Type of message sent",
            "example": "text"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "Timestamp when message was sent"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "message_id",
          "contact_id",
          "message_type",
          "timestamp"
        ],
        "title": "APIFreeMessageResponse",
        "description": "Schema for free-form message send response"
      },
      "APIGroupContactsPhoneRequest": {
        "properties": {
          "phone_numbers": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "minItems": 1,
            "title": "Phone Numbers",
            "description": "Phone numbers (8-15 digits, with country code, e.g. 919066666666) to add or remove"
          }
        },
        "type": "object",
        "required": [
          "phone_numbers"
        ],
        "title": "APIGroupContactsPhoneRequest",
        "description": "Schema for adding/removing contacts to/from a group by phone number"
      },
      "APIGroupContactsPhoneResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message"
          },
          "group_id": {
            "type": "string",
            "title": "Group Id",
            "description": "Group ID"
          },
          "phone_numbers": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Phone Numbers",
            "description": "Phone numbers from the request"
          },
          "added": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Added",
            "description": "Phone numbers newly added to the group"
          },
          "removed": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Removed",
            "description": "Phone numbers removed from the group"
          },
          "already_in_group": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Already In Group",
            "description": "Phone numbers that already existed in the group"
          },
          "not_found": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Not Found",
            "description": "Phone numbers with no matching contact in your account"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "group_id",
          "phone_numbers"
        ],
        "title": "APIGroupContactsPhoneResponse",
        "description": "Schema for phone-based group contact modification responses"
      },
      "APIGroupContactsRequest": {
        "properties": {
          "contact_ids": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "minItems": 1,
            "title": "Contact Ids",
            "description": "List of contact IDs to add or remove"
          }
        },
        "type": "object",
        "required": [
          "contact_ids"
        ],
        "title": "APIGroupContactsRequest",
        "description": "Schema for adding/removing contacts to/from a group"
      },
      "APIGroupContactsResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message"
          },
          "group_id": {
            "type": "string",
            "title": "Group Id",
            "description": "Group ID"
          },
          "contact_ids": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Contact Ids",
            "description": "Affected contact IDs"
          },
          "added": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Added",
            "description": "Contact IDs that were newly added"
          },
          "already_in_group": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Already In Group",
            "description": "Contact IDs that already existed in the group"
          },
          "failed": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Failed",
            "description": "Contact IDs that failed validation (invalid or not found)"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "group_id",
          "contact_ids"
        ],
        "title": "APIGroupContactsResponse",
        "description": "Schema for group contact modification responses"
      },
      "APIGroupCreateRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Name",
            "description": "Group name (must be unique per account)"
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Group description"
          },
          "contact_ids": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contact Ids",
            "description": "List of contact IDs to add to the group"
          },
          "tags": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tags",
            "description": "Tags for the group"
          }
        },
        "type": "object",
        "required": [
          "name"
        ],
        "title": "APIGroupCreateRequest",
        "description": "Schema for creating a contact group via public API"
      },
      "APIGroupDeleteResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message"
          },
          "group_id": {
            "type": "string",
            "title": "Group Id",
            "description": "Deleted group ID"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "group_id"
        ],
        "title": "APIGroupDeleteResponse",
        "description": "Schema for group deletion response"
      },
      "APIGroupItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Group ID"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Group name"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Group description"
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Tags",
            "description": "Group tags"
          },
          "contact_count": {
            "type": "integer",
            "title": "Contact Count",
            "description": "Number of contacts in group",
            "default": 0
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At",
            "description": "Creation timestamp"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "title": "APIGroupItem",
        "description": "Schema for a single contact group in API responses"
      },
      "APIGroupListResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "groups": {
            "items": {
              "$ref": "#/components/schemas/APIGroupItem"
            },
            "type": "array",
            "title": "Groups",
            "description": "List of groups"
          },
          "total": {
            "type": "integer",
            "title": "Total",
            "description": "Total number of groups"
          },
          "page": {
            "type": "integer",
            "title": "Page",
            "description": "Current page"
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "Page size"
          }
        },
        "type": "object",
        "required": [
          "status",
          "groups",
          "total",
          "page",
          "limit"
        ],
        "title": "APIGroupListResponse",
        "description": "Schema for paginated group list response"
      },
      "APIGroupResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message"
          },
          "group": {
            "$ref": "#/components/schemas/APIGroupItem",
            "description": "Group data"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "group"
        ],
        "title": "APIGroupResponse",
        "description": "Schema for single group operation responses"
      },
      "APIMessageSendRequest": {
        "properties": {
          "template_name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Template Name",
            "description": "Template name (must match an existing approved template)",
            "example": "order_confirmation"
          },
          "contact_phone": {
            "type": "string",
            "maxLength": 15,
            "minLength": 8,
            "title": "Contact Phone",
            "description": "Destination phone number (with country code, e.g., +1234567890)",
            "example": "+1234567890"
          },
          "contact_name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Contact Name",
            "description": "Name of the contact. Only used when creating a new (unsaved) contact. If omitted, defaults to 'User #<6-digit number>'",
            "example": "John Doe"
          },
          "body_data": {
            "additionalProperties": true,
            "type": "object",
            "title": "Body Data",
            "description": "\n        Body template variables as key-value pairs.\n\n        For POSITIONAL variables ({{1}}, {{2}}, {{3}}):\n        {\n            \"1\": \"John\",\n            \"2\": \"Premium Plan\",\n            \"3\": \"$99\"\n        }\n\n        For NAMED variables ({{name}}, {{company}}):\n        {\n            \"name\": \"John\",\n            \"company\": \"Acme Corp\",\n            \"amount\": \"$99\"\n        }\n\n        Keys must match exactly what's in the template (case-sensitive for named variables).\n        ",
            "example": {
              "1": "John",
              "2": "Premium Plan",
              "3": "$99"
            }
          },
          "header_data": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Header Data",
            "description": "\n        Header template variables as key-value pairs. Use this when the template has a TEXT\n        header containing variables (e.g. {{1}}) that are different from the body variables.\n        If not provided, header variables fall back to body_data values.\n\n        Example for a template with header \"{{1}}\" and body \"Hello {{1}}\":\n        {\n            \"header_data\": {\"1\": \"Daily Checkup\"},\n            \"body_data\": {\"1\": \"Rahul\"}\n        }\n        ",
            "example": {
              "1": "Daily Checkup"
            }
          },
          "url_button_data": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url Button Data",
            "description": "\n        Value for a \"Visit website\" (URL) button whose URL ends in a variable.\n        A URL button carries exactly one variable, so pass the value directly:\n\n        Example for a template with the button\n        `https://shop.example.com/track?id={{1}}`:\n        {\n            \"url_button_data\": \"ORD-12345\"\n        }\n\n        A template may carry a second URL button. To address them individually,\n        pass an object keyed by the button's position in the template (\"0\" for\n        the first button, \"1\" for the second):\n        {\n            \"url_button_data\": {\"0\": \"ORD-12345\", \"1\": \"REF-99\"}\n        }\n\n        Also accepted: a key naming the URL variable (`{\"order_id\": \"...\"}`),\n        and a list in button order (`[\"ORD-12345\"]`). A numeric key is read as\n        a 0-based position first, so \"1\" means the second button whenever that\n        button is the dynamic one, and otherwise falls through to the\n        template's only dynamic URL button.\n\n        Pass the value **unencoded** - special characters (spaces, ':', '|',\n        accented letters) are percent-encoded for you. Buttons omitted here\n        fall back to the template's example value. Static URL buttons take no\n        value and must not be listed.\n        ",
            "example": "ORD-12345"
          },
          "media_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Media Url",
            "description": "Media URL (required if template has media header). Must be publicly accessible HTTPS URL",
            "example": "https://example.com/image.jpg"
          },
          "filename": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Filename",
            "description": "Filename for document templates. If not provided, defaults to 'untitled'",
            "example": "invoice.pdf"
          },
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "Optional: Specify which WhatsApp Business Account phone ID to use. If not provided, uses template's default or user's first phone ID",
            "example": "123456789012345"
          },
          "expiration_time_ms": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiration Time Ms",
            "description": "Expiration time in milliseconds for limited-time offer templates. Required when sending a limited-time offer template",
            "example": 1209600000
          },
          "carousel_data": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Carousel Data",
            "description": "\n        Per-card data for carousel templates. Required when sending a carousel template.\n        Must contain exactly the same number of items as the template's card count.\n\n        Each item is an object with:\n        - media_url (str, required): Publicly accessible URL for the card's image/video header\n        - media_id (str, optional): WhatsApp media ID (takes precedence over media_url)\n        - body_data (dict, optional): Card body variable values e.g. {\"1\": \"value\"}\n        - button_payloads (list[str], optional): Payloads for quick-reply buttons (in order)\n        - url_button_params (list[str], optional): Dynamic URL suffix values for URL buttons (in order)\n\n        Example for a 3-card carousel:\n        [\n            {\"media_url\": \"https://example.com/card1.jpg\", \"button_payloads\": [\"more-like-this\"], \"url_button_params\": [\"product-1\"]},\n            {\"media_url\": \"https://example.com/card2.jpg\", \"button_payloads\": [\"more-like-this\"], \"url_button_params\": [\"product-2\"]},\n            {\"media_url\": \"https://example.com/card3.jpg\", \"button_payloads\": [\"more-like-this\"], \"url_button_params\": [\"product-3\"]}\n        ]\n        "
          },
          "order_details": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Order Details",
            "description": "\n        Order details action payload for templates with ORDER_DETAILS buttons.\n        Required when sending a template that has an ORDER_DETAILS button type.\n        Sent to Meta as-is as the button's action, so it must include the\n        outer \"order_details\" key - omitting it is rejected by Meta with\n        error 100 (\"Unexpected key ... on param ... action\").\n        \"payment_configuration\" must be a configuration_name already active\n        on the sending WABA (see GET /api/ecommerce/payment-configurations)\n        - an unknown name is rejected by Meta with error 131009.\n        \"payment_type\" is a closed Meta enum keyed off the gateway\n        (confirmed live: upi / br / payment_gateway:razorpay /\n        payment_gateway:payu / mx / upr) - NOT a free-form echo of the\n        provider name.\n\n        Example:\n        {\n            \"order_details\": {\n                \"reference_id\": \"order_123\",\n                \"type\": \"digital-goods\",\n                \"currency\": \"INR\",\n                \"total_amount\": {\"offset\": 100, \"value\": 10000},\n                \"order\": {\n                    \"status\": \"pending\",\n                    \"items\": [\n                        {\n                            \"retailer_id\": \"product_123\",\n                            \"name\": \"Product name\",\n                            \"amount\": {\"offset\": 100, \"value\": 10000},\n                            \"quantity\": 1\n                        }\n                    ],\n                    \"subtotal\": {\"offset\": 100, \"value\": 10000},\n                    \"tax\": {\"offset\": 100, \"value\": 0},\n                    \"shipping\": {\"offset\": 100, \"value\": 0}\n                },\n                \"payment_type\": \"payment_gateway:razorpay\",\n                \"payment_configuration\": \"your_configuration_name\"\n            }\n        }\n        "
          },
          "order_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Order Id",
            "description": "Id of an existing order from GET /api/orders that this payment request is for. Links the send to that order, so the payment Meta reports later settles it instead of opening an unrelated second order. Omit for a payment request with no stored order behind it - one is created from the order_details payload.",
            "example": "66b1f0c2a1b2c3d4e5f60718"
          },
          "order_status": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Order Status",
            "description": "\n        Order status payload for an ORDER_STATUS template. Required when\n        sending one - Meta models it as a UTILITY template with\n        sub_category ORDER_STATUS and no buttons, so the status rides a\n        top-level \"order_status\" component rather than a button action.\n\n        \"reference_id\" must be the reference of an order Meta already knows\n        about (the one sent with the original order_details message).\n        \"order.status\" is one of: processing, partially_shipped, shipped,\n        completed, canceled. Meta rejects an illegal transition with error\n        2046. \"order.description\" is optional and truncated to 120 chars.\n\n        Example:\n        {\n            \"reference_id\": \"order_123\",\n            \"order\": {\"status\": \"shipped\", \"description\": \"Out for delivery\"}\n        }\n        ",
            "example": {
              "order": {
                "description": "Out for delivery",
                "status": "shipped"
              },
              "reference_id": "order_123"
            }
          },
          "catalog_product_retailer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Catalog Product Retailer Id",
            "description": "Product to use as the CATALOG button's thumbnail, for templates with a CATALOG button. Optional - when omitted, a product from the catalog attached to the sending WhatsApp number is used.",
            "example": "product_123"
          },
          "mpm_sections": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mpm Sections",
            "description": "Product sections for templates with an MPM (multi-product) button. Required for MPM templates. Shape: [{\"title\": str, \"product_items\": [{\"product_retailer_id\": str}, ...]}, ...] (max 10 sections / 30 products)."
          },
          "spm_product": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Spm Product",
            "description": "Product for single-product (SPM) templates - ones with a PRODUCT header. Required for SPM templates. Shape: {\"catalog_id\": str, \"product_retailer_id\": str}."
          }
        },
        "type": "object",
        "required": [
          "template_name",
          "contact_phone"
        ],
        "title": "APIMessageSendRequest",
        "description": "Schema for sending message via public API - template-based"
      },
      "APIMessageSendResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status: 'success' or 'error'",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message",
            "example": "Message sent successfully"
          },
          "message_id": {
            "type": "string",
            "title": "Message Id",
            "description": "WhatsApp message ID",
            "example": "wamid.xxx"
          },
          "contact_id": {
            "type": "string",
            "title": "Contact Id",
            "description": "Contact ID (created or existing)",
            "example": "507f1f77bcf86cd799439012"
          },
          "template_name": {
            "type": "string",
            "title": "Template Name",
            "description": "Template name used",
            "example": "order_confirmation"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "Timestamp when message was sent",
            "example": "2024-06-15T10:00:00Z"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "message_id",
          "contact_id",
          "template_name",
          "timestamp"
        ],
        "title": "APIMessageSendResponse",
        "description": "Schema for API message send response"
      },
      "APIPhoneContactDeleteResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message"
          },
          "contact_id": {
            "type": "string",
            "title": "Contact Id",
            "description": "Deleted contact ID"
          },
          "phone_number": {
            "type": "string",
            "title": "Phone Number",
            "description": "Normalized phone number of the deleted contact"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "contact_id",
          "phone_number"
        ],
        "title": "APIPhoneContactDeleteResponse",
        "description": "Schema for phone-based contact deletion response"
      },
      "APITemplateBodyRequest": {
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 1024,
            "minLength": 1,
            "title": "Text",
            "description": "Body text with {{1}}/{{Name}} style variables"
          },
          "examples": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Examples",
            "description": "Example values for body variables. e.g. {\"1\": \"John\", \"2\": \"Order123\"} or {\"Name\": \"John\"}"
          }
        },
        "type": "object",
        "required": [
          "text"
        ],
        "title": "APITemplateBodyRequest",
        "description": "Body component for template creation"
      },
      "APITemplateButtonRequest": {
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "QUICK_REPLY",
              "URL",
              "PHONE_NUMBER",
              "COPY_CODE",
              "FLOW"
            ],
            "title": "Type",
            "description": "Button type"
          },
          "text": {
            "type": "string",
            "maxLength": 25,
            "title": "Text",
            "description": "Button label text"
          },
          "url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url",
            "description": "URL for URL buttons (supports {{1}} suffix)"
          },
          "url_example": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url Example",
            "description": "Example value for URL variable"
          },
          "phone_number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone Number",
            "description": "Phone number for PHONE_NUMBER buttons"
          },
          "copy_code_example": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Copy Code Example",
            "description": "Example coupon code for COPY_CODE buttons"
          },
          "flow_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flow Id",
            "description": "Flow ID for FLOW buttons"
          },
          "flow_action": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flow Action",
            "description": "Flow action",
            "default": "navigate"
          },
          "navigate_screen": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Navigate Screen",
            "description": "Target screen for FLOW buttons"
          }
        },
        "type": "object",
        "required": [
          "type",
          "text"
        ],
        "title": "APITemplateButtonRequest",
        "description": "Button component for template creation"
      },
      "APITemplateFooterRequest": {
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 60,
            "title": "Text",
            "description": "Footer text (no variables allowed)"
          }
        },
        "type": "object",
        "required": [
          "text"
        ],
        "title": "APITemplateFooterRequest",
        "description": "Footer component for template creation"
      },
      "APITemplateHeaderRequest": {
        "properties": {
          "format": {
            "type": "string",
            "enum": [
              "TEXT",
              "IMAGE",
              "VIDEO",
              "DOCUMENT",
              "LOCATION"
            ],
            "title": "Format",
            "description": "Header format type"
          },
          "text": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 60
              },
              {
                "type": "null"
              }
            ],
            "title": "Text",
            "description": "Header text (required when format is TEXT). Supports {{1}} or {{Name}} variables."
          },
          "text_example": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Text Example",
            "description": "Example values for header variables. e.g. {\"1\": \"John\"} or {\"Name\": \"John\"}"
          }
        },
        "type": "object",
        "required": [
          "format"
        ],
        "title": "APITemplateHeaderRequest",
        "description": "Header component for template creation"
      },
      "APITemplateItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Template ID",
            "example": "507f1f77bcf86cd799439012"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Template name",
            "example": "order_confirmation"
          },
          "category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Category",
            "description": "Template category",
            "example": "MARKETING"
          },
          "language": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Language",
            "description": "Template language code",
            "example": "en_US"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status",
            "description": "Meta approval status",
            "example": "APPROVED"
          },
          "header_format": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Header Format",
            "description": "Header type if present (TEXT, IMAGE, VIDEO, DOCUMENT)",
            "example": "IMAGE"
          },
          "header": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Header",
            "description": "Header text content (when header_format is TEXT)"
          },
          "body": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Body",
            "description": "Template body text",
            "example": "Hello {{1}}, your order {{2}} is confirmed."
          },
          "footer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Footer",
            "description": "Footer text content"
          },
          "buttons": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Buttons",
            "description": "Interactive buttons configuration"
          },
          "requires_media": {
            "type": "boolean",
            "title": "Requires Media",
            "description": "Whether this template requires a media URL when sending",
            "default": false
          },
          "component_types": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Component Types",
            "description": "List of component types in the template"
          },
          "media_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Media Type",
            "description": "Type of media required: image, document, video, location"
          },
          "variables": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Variables",
            "description": "Template variables with types and examples"
          },
          "requires_variables": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Requires Variables",
            "description": "Whether this template has variables to fill",
            "default": false
          },
          "variable_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Variable Count",
            "description": "Number of variables in template",
            "default": 0
          },
          "parameter_format": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Parameter Format",
            "description": "Parameter format: NAMED or POSITIONAL"
          },
          "example_data": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Example Data",
            "description": "Example data from Meta API including sample media URLs"
          },
          "sample_media_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sample Media Url",
            "description": "Sample media URL from Meta for preview"
          },
          "sub_category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sub Category",
            "description": "Meta sub-category if available"
          },
          "limited_time_offer": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Limited Time Offer",
            "description": "Limited-time offer component data"
          },
          "offer_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Offer Code",
            "description": "Offer/coupon code for LTO templates"
          },
          "is_carousel": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Carousel",
            "description": "Whether this is a carousel template",
            "default": false
          },
          "carousel_cards": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Carousel Cards",
            "description": "Card definitions for carousel templates"
          },
          "carousel_card_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Carousel Card Count",
            "description": "Number of cards in the carousel"
          },
          "quality_score": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Quality Score",
            "description": "Quality score from Meta: {score: GREEN|YELLOW|RED|UNKNOWN, date: unix_timestamp}"
          },
          "cta_url_link_tracking_opted_out": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cta Url Link Tracking Opted Out",
            "description": "Whether CTA URL link tracking is opted out",
            "default": false
          },
          "message_send_ttl_seconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message Send Ttl Seconds",
            "description": "Time-to-live for messages sent using this template (in seconds)"
          },
          "degrees_of_freedom_spec": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Degrees Of Freedom Spec",
            "description": "Degrees of freedom spec for template customization"
          },
          "api_payload_structure": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Api Payload Structure",
            "description": "Example request shape for sending this template via API"
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At",
            "description": "When the template was created"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "title": "APITemplateItem",
        "description": "Schema for a single template in the list response"
      },
      "APITemplateLTORequest": {
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 16,
            "minLength": 1,
            "title": "Text",
            "description": "Offer heading text (max 16 characters)"
          },
          "has_expiration": {
            "type": "boolean",
            "title": "Has Expiration",
            "description": "Whether to show the expiration countdown timer",
            "default": true
          }
        },
        "type": "object",
        "required": [
          "text"
        ],
        "title": "APITemplateLTORequest",
        "description": "Limited-time offer component"
      },
      "APITemplateListResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Request status",
            "example": "success"
          },
          "templates": {
            "items": {
              "$ref": "#/components/schemas/APITemplateItem"
            },
            "type": "array",
            "title": "Templates",
            "description": "List of templates"
          },
          "total": {
            "type": "integer",
            "title": "Total",
            "description": "Total number of templates",
            "example": 10
          }
        },
        "type": "object",
        "required": [
          "status",
          "templates",
          "total"
        ],
        "title": "APITemplateListResponse",
        "description": "Schema for list templates response"
      },
      "APITypingIndicatorRequest": {
        "properties": {
          "contact_phone": {
            "type": "string",
            "maxLength": 15,
            "minLength": 8,
            "title": "Contact Phone",
            "description": "Contact phone number with country code (e.g., +1234567890)",
            "example": "+1234567890"
          },
          "waba_phone_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Waba Phone Id",
            "description": "WhatsApp Business Account phone ID. Inferred from the contact's latest inbound message when omitted",
            "example": "123456789012345"
          }
        },
        "type": "object",
        "required": [
          "contact_phone"
        ],
        "title": "APITypingIndicatorRequest",
        "description": "Schema for showing a typing indicator via public API"
      },
      "APITypingIndicatorResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "'success' when the indicator was shown, 'skipped' when it could not be (e.g., no inbound message from this contact yet)",
            "example": "success"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Response message",
            "example": "Typing indicator sent"
          },
          "contact_phone": {
            "type": "string",
            "title": "Contact Phone",
            "description": "Normalized contact phone number",
            "example": "1234567890"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "Response timestamp"
          }
        },
        "type": "object",
        "required": [
          "status",
          "message",
          "contact_phone",
          "timestamp"
        ],
        "title": "APITypingIndicatorResponse",
        "description": "Schema for typing indicator response"
      },
      "CatalogMessageSchema": {
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "catalog_message",
              "product",
              "product_list"
            ],
            "title": "Type"
          },
          "catalog_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Catalog Id",
            "description": "Meta catalog id - required for 'product' and 'product_list'"
          },
          "product_retailer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Product Retailer Id",
            "description": "Product retailer_id - required for type 'product'"
          },
          "thumbnail_product_retailer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Thumbnail Product Retailer Id",
            "description": "Optional thumbnail product for type 'catalog_message'"
          },
          "header_text": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Header Text",
            "description": "Header text - required for type 'product_list'"
          },
          "footer_text": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Footer Text",
            "description": "Optional footer text"
          },
          "sections": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/CatalogSectionSchema"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sections",
            "description": "Product sections - required for type 'product_list'"
          }
        },
        "type": "object",
        "required": [
          "type"
        ],
        "title": "CatalogMessageSchema",
        "description": "Send a WhatsApp catalog/product interactive message.\n\nhttps://developers.facebook.com/documentation/business-messaging/whatsapp/catalogs/catalog-messages\n\n- ``catalog_message``: lets the recipient browse the WABA's default\n  connected catalog. No ``catalog_id`` needed; ``thumbnail_product_retailer_id``\n  optionally picks the thumbnail product.\n- ``product``: a single product card. Requires ``catalog_id`` +\n  ``product_retailer_id``.\n- ``product_list``: a multi-section product list. Requires ``catalog_id``,\n  ``header_text``, and ``sections``.\n\n``message`` (on the parent request) is used as the body text for all\nthree types."
      },
      "CatalogProductItemSchema": {
        "properties": {
          "product_retailer_id": {
            "type": "string",
            "title": "Product Retailer Id",
            "description": "Meta catalog product retailer_id"
          }
        },
        "type": "object",
        "required": [
          "product_retailer_id"
        ],
        "title": "CatalogProductItemSchema",
        "description": "One product row inside a product_list section."
      },
      "CatalogSectionSchema": {
        "properties": {
          "title": {
            "type": "string",
            "title": "Title",
            "description": "Section heading shown above its products"
          },
          "product_items": {
            "items": {
              "$ref": "#/components/schemas/CatalogProductItemSchema"
            },
            "type": "array",
            "title": "Product Items",
            "description": "Products in this section (product_retailer_id only)"
          }
        },
        "type": "object",
        "required": [
          "title",
          "product_items"
        ],
        "title": "CatalogSectionSchema",
        "description": "One section of a product_list (Multi-Product) message."
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "QuickResponseButtonsSchema": {
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "reply",
              "cta_url"
            ],
            "title": "Type",
            "description": "Button group type"
          },
          "reply_buttons": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/ReplyButtonSchema"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reply Buttons",
            "description": "1-3 reply buttons; required when type is 'reply'"
          },
          "url_button": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UrlButtonSchema"
              },
              {
                "type": "null"
              }
            ],
            "description": "URL button; required when type is 'cta_url'"
          }
        },
        "type": "object",
        "required": [
          "type"
        ],
        "title": "QuickResponseButtonsSchema",
        "description": "Interactive buttons attached to a quick response.\n\nA message carries EITHER up to 3 reply buttons OR exactly one URL button --\nnever both (WhatsApp session-message rule)."
      },
      "ReplyButtonSchema": {
        "properties": {
          "id": {
            "type": "string",
            "maxLength": 256,
            "minLength": 1,
            "title": "Id",
            "description": "Internal button id echoed back by WhatsApp when tapped"
          },
          "title": {
            "type": "string",
            "maxLength": 20,
            "minLength": 1,
            "title": "Title",
            "description": "Button label shown to the customer"
          }
        },
        "type": "object",
        "required": [
          "id",
          "title"
        ],
        "title": "ReplyButtonSchema",
        "description": "A single quick-reply button."
      },
      "UrlButtonSchema": {
        "properties": {
          "display_text": {
            "type": "string",
            "maxLength": 20,
            "minLength": 1,
            "title": "Display Text",
            "description": "Button label"
          },
          "url": {
            "type": "string",
            "maxLength": 2048,
            "minLength": 1,
            "title": "Url",
            "description": "Destination URL"
          }
        },
        "type": "object",
        "required": [
          "display_text",
          "url"
        ],
        "title": "UrlButtonSchema",
        "description": "A single URL ('Visit Website') button."
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    },
    "securitySchemes": {
      "HTTPBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your Waplify API key, sent as `Authorization: Bearer wapl_...`. Create keys in the Waplify app under Developers > API."
      }
    }
  }
}
