{
  "openapi": "3.1.0",
  "info": {
    "title": "WahaSend API",
    "version": "1",
    "summary": "Send and receive WhatsApp messages from your own number.",
    "description": "Full guides: https://wahasend.com/docs (Markdown for agents: https://wahasend.com/llms.txt). Every error answers {success: false, error: {code, message, details?, requestId}}; the codes are listed at https://wahasend.com/docs/errors.md.",
    "contact": {
      "name": "WahaSend",
      "url": "https://wahasend.com",
      "email": "contact@wahasend.com"
    },
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    }
  },
  "externalDocs": {
    "description": "WahaSend API docs",
    "url": "https://wahasend.com/docs"
  },
  "servers": [
    {
      "url": "https://app.wahasend.com/api/v1"
    }
  ],
  "security": [
    {
      "ApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Sending messages",
      "description": "One text message comes with every product. Photos, files, voice notes, contacts, locations, links, polls, forwarding, editing and deleting come with **Developer** (feature `media`)."
    },
    {
      "name": "Validate numbers",
      "description": "Find out which numbers are on WhatsApp before you write to them. Comes with **Notify**, **Developer** and **Connect** (feature `batch`). Nothing is sent."
    },
    {
      "name": "Batch sends",
      "description": "The same text to up to 500 people in one call. Comes with **Notify**, **Developer** and **Connect** (feature `batch`). For personalised texts and scheduling, use [campaigns](https://wahasend.com/docs/api/campaigns.md)."
    },
    {
      "name": "Campaigns",
      "description": "A campaign sends a template with `{{variables}}` to a list, spaced 3–7 seconds apart per message, now or at a set time. Comes with **Notify** (feature `campaigns`). Statuses: `draft` ⇄ `scheduled` → `sending` ⇄ `paused` → `completed`; `scheduled` or `paused` → `cancelled`. `stats` counts `sent`, `failed`, `delivered` and `read` (from WhatsApp's receipts, each message once)."
    },
    {
      "name": "Reminders",
      "description": "A reminder is a message to one person at a set time, once or repeated daily, weekly or monthly (monthly keeps the day of the month; the 31st becomes the last day of shorter months). Checked every 30 seconds. Comes with **Notify** (feature `reminders`). Statuses: `scheduled`, `processing`, `done`, `failed`, `cancelled`."
    },
    {
      "name": "One-time codes (OTP)",
      "description": "Send a verification code by WhatsApp and check what the person typed. Codes are random, stored hashed, valid 5 minutes, 3 tries. Comes with **Developer** (feature `otp`)."
    },
    {
      "name": "Chats and contacts",
      "description": "Read what your number sent and received, one conversation per person, and look up contacts. Comes with **Connect** (feature `inbox`). A person is keyed by their phone digits, or by their `@lid` id when WhatsApp hides the number."
    },
    {
      "name": "WhatsApp numbers",
      "description": "Check and link your numbers from code. Every product can call these. A per-number key sees only its own number; with the account key, pick one with `containerId` (from `GET /session/list`). Adding and removing numbers is done in the dashboard. Notify, Assistant and Shop add as many numbers as they need. With Developer or Connect active, the account has 3 numbers included, plus the extra numbers it buys ($10 a month each, from the dashboard's Subscription page); adding one more answers 403 `NUMBER_LIMIT_REACHED`. Numbers you already have are never removed: an account above its allowance keeps sending from all of them."
    },
    {
      "name": "Account, history and keys",
      "description": "Who you are, what was sent, and your keys. Every product can read these and create API keys (see [Which products can use the API](https://wahasend.com/docs/authentication.md))."
    },
    {
      "name": "Webhook address and signing secret",
      "description": "Where WahaSend posts [events](https://wahasend.com/docs/webhooks.md), and the secret that signs them. **Developer** gets every event (feature `webhooks`); **Assistant** and **Shop** owners can set a webhook too, for their own events (`bot.*`, and `commerce.order` with Shop)."
    }
  ],
  "paths": {
    "/alert/send": {
      "post": {
        "operationId": "alert-send",
        "summary": "Send a text message",
        "description": "Queues one text message. It goes out a few seconds later with a typing indicator, like a person would send it (`high` priority skips that). The number is checked on WhatsApp first.\n\nFollow the message with `GET /messages` or the `message.*` [webhook events](https://wahasend.com/docs/webhooks.md). `messageId` is WahaSend's id, not WhatsApp's. `containerId` is the number it is queued on; with [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) it can move to another number of the group if that one goes down, and `GET /messages` and the webhooks then show the number that really sent it.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-send",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "International phone number (`+22212345678`) or a WhatsApp id ending in `@lid`. See [Phone numbers](https://wahasend.com/docs/phone-numbers.md)."
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096,
                    "description": "The text, 1–4096 characters. Links get a preview."
                  },
                  "priority": {
                    "type": "string",
                    "enum": [
                      "high",
                      "normal",
                      "low"
                    ],
                    "default": "normal",
                    "description": "Default `normal`. `high` jumps the queue and skips the typing simulation; use it for time-critical alerts only."
                  }
                },
                "required": [
                  "phone",
                  "message"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "message": "Your order #1042 is ready for pickup.",
                "priority": "normal"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "4f0c6a1e-2b7d-4c1a-9e35-7d8f2a6b1c90",
                  "status": "queued",
                  "priority": "normal",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NUMBER_NOT_ON_WHATSAPP, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "NUMBER_VALIDATION_UNAVAILABLE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/send-image": {
      "post": {
        "operationId": "alert-send-image",
        "summary": "Send a photo",
        "description": "Sends an image from a link, with an optional caption.\n\nSent right away through your number (no queue, no typing simulation) and recorded in `GET /messages` as `sent`, so `message.delivered` / `message.read` [events](https://wahasend.com/docs/webhooks.md) follow. `messageId` is WahaSend's id (use it to edit, delete or forward the message); `wahaMessageId` is WhatsApp's.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-send-image",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "International phone number (`+22212345678`) or a WhatsApp id ending in `@lid`. See [Phone numbers](https://wahasend.com/docs/phone-numbers.md)."
                  },
                  "imageUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "Link to the image (JPEG, PNG or WebP). Must be a public address: private and local addresses are refused."
                  },
                  "caption": {
                    "type": "string",
                    "maxLength": 1024,
                    "description": "Text under the file, up to 1024 characters."
                  },
                  "filename": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "File name shown to the contact, up to 255 characters."
                  },
                  "mimetype": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "MIME type, e.g. `application/pdf` (up to 100 characters). Guessed when missing."
                  }
                },
                "required": [
                  "phone",
                  "imageUrl"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "imageUrl": "https://example.com/menu.jpg",
                "caption": "Today's menu"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "3d7f1b2c-5e8a-4c69-b0d3-8f2a6c4e1b95",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/send-video": {
      "post": {
        "operationId": "alert-send-video",
        "summary": "Send a video",
        "description": "Sends an MP4 video from a link.\n\nSent right away through your number (no queue, no typing simulation) and recorded in `GET /messages` as `sent`, so `message.delivered` / `message.read` [events](https://wahasend.com/docs/webhooks.md) follow. `messageId` is WahaSend's id (use it to edit, delete or forward the message); `wahaMessageId` is WhatsApp's.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-send-video",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "International phone number (`+22212345678`) or a WhatsApp id ending in `@lid`. See [Phone numbers](https://wahasend.com/docs/phone-numbers.md)."
                  },
                  "videoUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "Link to the MP4 file. Must be a public address: private and local addresses are refused."
                  },
                  "caption": {
                    "type": "string",
                    "maxLength": 1024,
                    "description": "Text under the file, up to 1024 characters."
                  },
                  "filename": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "File name shown to the contact, up to 255 characters."
                  },
                  "mimetype": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "MIME type, e.g. `application/pdf` (up to 100 characters). Guessed when missing."
                  }
                },
                "required": [
                  "phone",
                  "videoUrl"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "videoUrl": "https://example.com/demo.mp4",
                "caption": "How it works"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "3d7f1b2c-5e8a-4c69-b0d3-8f2a6c4e1b95",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/send-file": {
      "post": {
        "operationId": "alert-send-file",
        "summary": "Send a file",
        "description": "Sends a document (PDF, spreadsheet…) from a link.\n\nSent right away through your number (no queue, no typing simulation) and recorded in `GET /messages` as `sent`, so `message.delivered` / `message.read` [events](https://wahasend.com/docs/webhooks.md) follow. `messageId` is WahaSend's id (use it to edit, delete or forward the message); `wahaMessageId` is WhatsApp's.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-send-file",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "International phone number (`+22212345678`) or a WhatsApp id ending in `@lid`. See [Phone numbers](https://wahasend.com/docs/phone-numbers.md)."
                  },
                  "fileUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "Link to the file. Must be a public address: private and local addresses are refused."
                  },
                  "filename": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "File name shown to the contact, up to 255 characters."
                  },
                  "caption": {
                    "type": "string",
                    "maxLength": 1024,
                    "description": "Text under the file, up to 1024 characters."
                  },
                  "mimetype": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "MIME type, e.g. `application/pdf` (up to 100 characters). Guessed when missing."
                  }
                },
                "required": [
                  "phone",
                  "fileUrl"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "fileUrl": "https://example.com/invoice-1042.pdf",
                "filename": "invoice-1042.pdf",
                "caption": "Your invoice"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "3d7f1b2c-5e8a-4c69-b0d3-8f2a6c4e1b95",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/send-voice": {
      "post": {
        "operationId": "alert-send-voice",
        "summary": "Send a voice note",
        "description": "Sends an audio file as a voice note. Use OGG/Opus for it to play as a voice note.\n\nSent right away through your number (no queue, no typing simulation) and recorded in `GET /messages` as `sent`, so `message.delivered` / `message.read` [events](https://wahasend.com/docs/webhooks.md) follow. `messageId` is WahaSend's id (use it to edit, delete or forward the message); `wahaMessageId` is WhatsApp's.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-send-voice",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "International phone number (`+22212345678`) or a WhatsApp id ending in `@lid`. See [Phone numbers](https://wahasend.com/docs/phone-numbers.md)."
                  },
                  "audioUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "Link to the audio file. Must be a public address: private and local addresses are refused."
                  }
                },
                "required": [
                  "phone",
                  "audioUrl"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "audioUrl": "https://example.com/welcome.ogg"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "3d7f1b2c-5e8a-4c69-b0d3-8f2a6c4e1b95",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/send-contact": {
      "post": {
        "operationId": "alert-send-contact",
        "summary": "Share contacts",
        "description": "Sends 1 to 10 contact cards.\n\nSent right away through your number (no queue, no typing simulation) and recorded in `GET /messages` as `sent`, so `message.delivered` / `message.read` [events](https://wahasend.com/docs/webhooks.md) follow. `messageId` is WahaSend's id (use it to edit, delete or forward the message); `wahaMessageId` is WhatsApp's.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-send-contact",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "International phone number (`+22212345678`) or a WhatsApp id ending in `@lid`. See [Phone numbers](https://wahasend.com/docs/phone-numbers.md)."
                  },
                  "contacts": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "fullName": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 255
                        },
                        "phoneNumber": {
                          "type": "string",
                          "minLength": 5,
                          "maxLength": 20
                        }
                      },
                      "required": [
                        "fullName",
                        "phoneNumber"
                      ],
                      "additionalProperties": false
                    },
                    "minItems": 1,
                    "maxItems": 10,
                    "description": "1–10 contacts."
                  }
                },
                "required": [
                  "phone",
                  "contacts"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "contacts": [
                  {
                    "fullName": "Front desk",
                    "phoneNumber": "+22245250000"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "3d7f1b2c-5e8a-4c69-b0d3-8f2a6c4e1b95",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/send-location": {
      "post": {
        "operationId": "alert-send-location",
        "summary": "Send a location",
        "description": "Sends a map pin.\n\nSent right away through your number (no queue, no typing simulation) and recorded in `GET /messages` as `sent`, so `message.delivered` / `message.read` [events](https://wahasend.com/docs/webhooks.md) follow. `messageId` is WahaSend's id (use it to edit, delete or forward the message); `wahaMessageId` is WhatsApp's.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-send-location",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "International phone number (`+22212345678`) or a WhatsApp id ending in `@lid`. See [Phone numbers](https://wahasend.com/docs/phone-numbers.md)."
                  },
                  "latitude": {
                    "type": "number",
                    "minimum": -90,
                    "maximum": 90,
                    "description": "−90 to 90."
                  },
                  "longitude": {
                    "type": "number",
                    "minimum": -180,
                    "maximum": 180,
                    "description": "−180 to 180."
                  },
                  "title": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Place name, up to 255 characters."
                  },
                  "address": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Address, up to 500 characters."
                  }
                },
                "required": [
                  "phone",
                  "latitude",
                  "longitude"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "latitude": 18.0858,
                "longitude": -15.9785,
                "title": "Our shop",
                "address": "Tevragh Zeina, Nouakchott"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "3d7f1b2c-5e8a-4c69-b0d3-8f2a6c4e1b95",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/send-link": {
      "post": {
        "operationId": "alert-send-link",
        "summary": "Send a link with a custom preview",
        "description": "Sends text with a link preview you choose (title, description, image).\n\nSent right away through your number (no queue, no typing simulation) and recorded in `GET /messages` as `sent`, so `message.delivered` / `message.read` [events](https://wahasend.com/docs/webhooks.md) follow. `messageId` is WahaSend's id (use it to edit, delete or forward the message); `wahaMessageId` is WhatsApp's.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-send-link",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "International phone number (`+22212345678`) or a WhatsApp id ending in `@lid`. See [Phone numbers](https://wahasend.com/docs/phone-numbers.md)."
                  },
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096,
                    "description": "Message text, 1–4096 characters. Include the link in it."
                  },
                  "previewUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "The link the preview is for. Must be a public address: private and local addresses are refused."
                  },
                  "previewTitle": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "Preview title, 1–255 characters."
                  },
                  "previewDescription": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Up to 500 characters."
                  },
                  "previewImageUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "Public link to the preview image."
                  }
                },
                "required": [
                  "phone",
                  "text",
                  "previewUrl",
                  "previewTitle"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "text": "Track your order: https://example.com/t/1042",
                "previewUrl": "https://example.com/t/1042",
                "previewTitle": "Order #1042"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "3d7f1b2c-5e8a-4c69-b0d3-8f2a6c4e1b95",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/send-poll": {
      "post": {
        "operationId": "alert-send-poll",
        "summary": "Send a poll",
        "description": "Sends a poll with 2 to 12 options. Votes arrive as `poll.vote` [webhook events](https://wahasend.com/docs/webhooks.md).\n\nSent right away through your number (no queue, no typing simulation) and recorded in `GET /messages` as `sent`, so `message.delivered` / `message.read` [events](https://wahasend.com/docs/webhooks.md) follow. `messageId` is WahaSend's id (use it to edit, delete or forward the message); `wahaMessageId` is WhatsApp's.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-send-poll",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "International phone number (`+22212345678`) or a WhatsApp id ending in `@lid`. See [Phone numbers](https://wahasend.com/docs/phone-numbers.md)."
                  },
                  "question": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "1–255 characters."
                  },
                  "options": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 100
                    },
                    "minItems": 2,
                    "maxItems": 12,
                    "description": "2–12 options, each 1–100 characters."
                  },
                  "multipleAnswers": {
                    "type": "boolean",
                    "default": false,
                    "description": "Allow several answers. Default `false`."
                  }
                },
                "required": [
                  "phone",
                  "question",
                  "options"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "question": "Which delivery day suits you?",
                "options": [
                  "Monday",
                  "Wednesday",
                  "Friday"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "3d7f1b2c-5e8a-4c69-b0d3-8f2a6c4e1b95",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/forward": {
      "post": {
        "operationId": "alert-forward",
        "summary": "Forward a message",
        "description": "Forwards a message your number has to another chat. The recipient sees \"Forwarded\". Recorded in `GET /messages` like the media sends.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-forward",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fromPhone": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 20,
                    "description": "Not needed (WhatsApp finds the message by its id); still accepted."
                  },
                  "messageId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "The message: WahaSend's `messageId` of a message you sent, or a WhatsApp id (e.g. `wahaMessageId` of a `message.inbound` event)."
                  },
                  "toPhone": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 20,
                    "pattern": "^\\+?[1-9]\\d{7,19}$",
                    "description": "International phone number, 8–20 characters (`+22212345678`). `@lid` ids are not accepted here."
                  }
                },
                "required": [
                  "messageId",
                  "toPhone"
                ],
                "additionalProperties": false
              },
              "example": {
                "messageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                "toPhone": "+22287654321"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "3d7f1b2c-5e8a-4c69-b0d3-8f2a6c4e1b95",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "MESSAGE_WRONG_NUMBER, PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "MESSAGE_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "MESSAGE_NOT_SENT",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/edit": {
      "put": {
        "operationId": "alert-edit",
        "summary": "Edit a sent message",
        "description": "Changes the text of a message your number sent. WhatsApp only allows this for a short while after sending.\n\nWith WahaSend's id the message is found in your history: it must be sent (`sent`, `delivered` or `read`, else `MESSAGE_NOT_SENT`), yours (else `MESSAGE_NOT_FOUND`) and from the number this request uses (a per-number key or `containerId`; else `MESSAGE_WRONG_NUMBER`). Its text in `GET /messages` is updated too.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-edit",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "The chat's phone number or `@lid` id. Required with a WhatsApp id; with WahaSend's id it is taken from the message (if given, it must match)."
                  },
                  "messageId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "The message to change. WahaSend's `messageId` (from `/alert/send`, a media send or `GET /messages`; the message must be sent), or WhatsApp's id as before (then `phone` is required)."
                  },
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096,
                    "description": "New text, 1–4096 characters."
                  }
                },
                "required": [
                  "messageId",
                  "text"
                ],
                "additionalProperties": false
              },
              "example": {
                "messageId": "4f0c6a1e-2b7d-4c1a-9e35-7d8f2a6b1c90",
                "text": "Your order #1042 is ready (counter 2)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "4f0c6a1e-2b7d-4c1a-9e35-7d8f2a6b1c90",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "MESSAGE_WRONG_NUMBER, PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "MESSAGE_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "MESSAGE_NOT_SENT",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/delete": {
      "post": {
        "operationId": "alert-delete",
        "summary": "Delete a sent message",
        "description": "Deletes a message your number sent, for everyone.\n\nSame rules as [edit](https://wahasend.com/docs/api/sending.md#alert-edit). With a WhatsApp id, send `phone` too: `{ \"phone\": \"+22212345678\", \"messageId\": \"true_…\" }`.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-delete",
        "tags": [
          "Sending messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 7,
                    "maxLength": 64,
                    "description": "The chat's phone number or `@lid` id. Required with a WhatsApp id; with WahaSend's id it is taken from the message (if given, it must match)."
                  },
                  "messageId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "The message to delete. WahaSend's `messageId` (from `/alert/send`, a media send or `GET /messages`; the message must be sent), or WhatsApp's id as before (then `phone` is required)."
                  }
                },
                "required": [
                  "messageId"
                ],
                "additionalProperties": false
              },
              "example": {
                "messageId": "4f0c6a1e-2b7d-4c1a-9e35-7d8f2a6b1c90"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messageId": "4f0c6a1e-2b7d-4c1a-9e35-7d8f2a6b1c90",
                  "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "MESSAGE_WRONG_NUMBER, PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "MESSAGE_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "MESSAGE_NOT_SENT",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alert/validate": {
      "post": {
        "operationId": "alert-validate",
        "summary": "Check up to 500 numbers",
        "description": "Returns the numbers that are on WhatsApp and those that aren't, as digits. `@lid` ids count as valid.\n\nWhen **none** of the numbers is on WhatsApp the answer is a 400 `NO_VALID_NUMBERS` error with `details.invalidNumbers`, not an empty `valid` list.\n\nUnlocked by: Notify, Developer, Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-validate",
        "tags": [
          "Validate numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phones": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 7,
                      "maxLength": 64
                    },
                    "minItems": 1,
                    "maxItems": 500,
                    "description": "1–500 phone numbers or `@lid` ids."
                  }
                },
                "required": [
                  "phones"
                ],
                "additionalProperties": false
              },
              "example": {
                "phones": [
                  "+22212345678",
                  "+22287654321"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "valid": [
                    "22212345678"
                  ],
                  "invalid": [
                    "22287654321"
                  ],
                  "total": 2
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_VALID_NUMBERS, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "NUMBER_VALIDATION_UNAVAILABLE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/recipients/validate": {
      "post": {
        "operationId": "recipients-validate",
        "summary": "Check a long list (up to 10,000)",
        "description": "For contact lists: removes duplicates, checks the format, then asks WhatsApp five numbers at a time. Slower; use it before a campaign.\n\nA number WhatsApp could not be asked about is listed as valid with an empty `chatId`.\n\nUnlocked by: Notify, Developer, Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#recipients-validate",
        "tags": [
          "Validate numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phones": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1
                    },
                    "minItems": 1,
                    "maxItems": 10000,
                    "description": "1–10,000 phone numbers. Spaces, dashes and brackets are removed."
                  },
                  "containerId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number."
                  }
                },
                "required": [
                  "phones"
                ],
                "additionalProperties": false
              },
              "example": {
                "phones": [
                  "+222 12 34 56 78",
                  "+22287654321",
                  "12"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "total": 3,
                  "valid": 1,
                  "invalid": 2,
                  "validNumbers": [
                    {
                      "phone": "+22212345678",
                      "chatId": "22212345678@c.us"
                    }
                  ],
                  "invalidNumbers": [
                    {
                      "phone": "12",
                      "reason": "Invalid format",
                      "code": "invalid_format"
                    },
                    {
                      "phone": "+22287654321",
                      "reason": "Not on WhatsApp",
                      "code": "not_on_whatsapp"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/alert/batch": {
      "post": {
        "operationId": "alert-batch",
        "summary": "Send one text to many",
        "description": "Checks every number on WhatsApp, skips the ones that aren't, and queues one message per remaining recipient.\n\nSending the same text to many people who didn't ask for it is the fastest way to get a number banned. See [Good practice](https://wahasend.com/docs/good-practice.md).\n\nUnlocked by: Notify, Developer, Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#alert-batch",
        "tags": [
          "Batch sends"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipients": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 7,
                      "maxLength": 64
                    },
                    "minItems": 1,
                    "maxItems": 500,
                    "description": "1–500 phone numbers or `@lid` ids."
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096,
                    "description": "1–4096 characters."
                  },
                  "priority": {
                    "type": "string",
                    "enum": [
                      "high",
                      "normal",
                      "low"
                    ],
                    "default": "normal",
                    "description": "Default `normal`."
                  },
                  "skipInvalidNumbers": {
                    "type": "boolean",
                    "default": true,
                    "description": "Default `true`: numbers not on WhatsApp are skipped and listed in `invalidNumbers`. `false`: if any number is not on WhatsApp, nothing is sent (`NUMBER_NOT_ON_WHATSAPP` with `details.invalidNumbers`)."
                  }
                },
                "required": [
                  "recipients",
                  "message"
                ],
                "additionalProperties": false
              },
              "example": {
                "recipients": [
                  "+22212345678",
                  "+22287654321"
                ],
                "message": "We are closed on Friday for the holiday."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "count": 1,
                  "messages": [
                    {
                      "phone": "22212345678",
                      "messageId": "4f0c6a1e-2b7d-4c1a-9e35-7d8f2a6b1c90",
                      "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                    }
                  ],
                  "invalidNumbers": [
                    "22287654321"
                  ],
                  "skipped": 1
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, NO_VALID_NUMBERS, NUMBER_NOT_ON_WHATSAPP, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "NUMBER_VALIDATION_UNAVAILABLE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/bulk/campaigns": {
      "post": {
        "operationId": "campaign-create",
        "summary": "Create a campaign",
        "description": "Saves it as a `draft`, or `scheduled` when you give `scheduledAt`. Nothing is sent until you call send (or the time comes).\n\nUnlocked by: Notify. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#campaign-create",
        "tags": [
          "Campaigns"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "1–255 characters."
                  },
                  "template": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096,
                    "description": "1–4096 characters. `{{name}}`-style placeholders are filled from each recipient's `variables` (any language in the keys)."
                  },
                  "recipients": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "phone": {
                          "type": "string",
                          "minLength": 8,
                          "maxLength": 20,
                          "pattern": "^\\+?[1-9]\\d{7,19}$"
                        },
                        "variables": {
                          "type": "object",
                          "additionalProperties": {
                            "type": "string"
                          }
                        }
                      },
                      "required": [
                        "phone"
                      ],
                      "additionalProperties": false
                    },
                    "minItems": 1,
                    "maxItems": 10000,
                    "description": "1–10,000 recipients."
                  },
                  "scheduledAt": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When to start, with any offset: `2026-10-05T08:00:00Z` or `2026-10-05T08:00:00+00:00` (Nouakchott is UTC). Checked every minute; it starts from your default number."
                  }
                },
                "required": [
                  "name",
                  "template",
                  "recipients"
                ],
                "additionalProperties": false
              },
              "example": {
                "name": "Ramadan hours",
                "template": "Hello {{name}}, from Monday we open 10:00–16:00.",
                "recipients": [
                  {
                    "phone": "+22212345678",
                    "variables": {
                      "name": "Aïcha"
                    }
                  },
                  {
                    "phone": "+22287654321",
                    "variables": {
                      "name": "Moussa"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "campaign": {
                    "id": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
                    "name": "Ramadan hours",
                    "status": "draft",
                    "recipientCount": 2,
                    "scheduledAt": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "operationId": "campaign-list",
        "summary": "List campaigns",
        "description": "Every campaign of the organization, oldest first.\n\nUnlocked by: Notify. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#campaign-list",
        "tags": [
          "Campaigns"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "campaigns": [
                    {
                      "id": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
                      "name": "Ramadan hours",
                      "template": "Hello {{name}}, from Monday we open 10:00–16:00.",
                      "status": "completed",
                      "stats": {
                        "total": 2,
                        "sent": 2,
                        "delivered": 2,
                        "failed": 0,
                        "read": 1
                      },
                      "scheduledAt": null,
                      "createdAt": "2026-09-30T09:12:44.120Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/bulk/campaigns/{id}/status": {
      "get": {
        "operationId": "campaign-status",
        "summary": "Campaign status",
        "description": "Where a campaign stands, with its recipients and counts.\n\n`delivered` counts a message the first time WhatsApp reports it delivered or read; `read` the first time it is read. Campaigns from before 2026-10-01 have no `read`.\n\nUnlocked by: Notify. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#campaign-status",
        "tags": [
          "Campaigns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Campaign id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "id": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
                  "name": "Ramadan hours",
                  "template": "Hello {{name}}, from Monday we open 10:00–16:00.",
                  "recipients": [
                    {
                      "phone": "+22212345678",
                      "variables": {
                        "name": "Aïcha"
                      }
                    }
                  ],
                  "status": "sending",
                  "stats": {
                    "total": 2,
                    "sent": 1,
                    "delivered": 1,
                    "failed": 0,
                    "read": 0
                  },
                  "scheduledAt": null,
                  "startedAt": "2026-09-30T09:15:02.000Z",
                  "completedAt": null,
                  "createdAt": "2026-09-30T09:12:44.120Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/bulk/campaigns/{id}": {
      "put": {
        "operationId": "campaign-update",
        "summary": "Edit before it starts",
        "description": "Changes the name, template, recipients or start time of a `draft` or `scheduled` campaign.\n\nUnlocked by: Notify. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#campaign-update",
        "tags": [
          "Campaigns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Campaign id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "1–255 characters."
                  },
                  "template": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096,
                    "description": "1–4096 characters."
                  },
                  "recipients": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "phone": {
                          "type": "string",
                          "minLength": 8,
                          "maxLength": 20,
                          "pattern": "^\\+?[1-9]\\d{7,19}$"
                        },
                        "variables": {
                          "type": "object",
                          "additionalProperties": {
                            "type": "string"
                          }
                        }
                      },
                      "required": [
                        "phone"
                      ],
                      "additionalProperties": false
                    },
                    "minItems": 1,
                    "maxItems": 10000,
                    "description": "Replaces the whole list (1–10,000)."
                  },
                  "scheduledAt": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date-time"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "A new start time (any offset) makes it `scheduled`; `null` makes it a `draft` again."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "template": "Hello {{name}}, from Monday we open 10:00–16:30.",
                "scheduledAt": "2026-10-05T08:00:00+00:00"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "campaign": {
                    "id": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
                    "name": "Ramadan hours",
                    "template": "Hello {{name}}, from Monday we open 10:00–16:30.",
                    "status": "scheduled",
                    "stats": {
                      "total": 2,
                      "sent": 0,
                      "delivered": 0,
                      "failed": 0
                    },
                    "scheduledAt": "2026-10-05T08:00:00.000Z",
                    "createdAt": "2026-09-30T09:12:44.120Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "CAMPAIGN_INVALID_STATE, VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "campaign-delete",
        "summary": "Delete",
        "description": "Deletes a campaign that is not `sending` (pause it first) and its message history.\n\nUnlocked by: Notify. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#campaign-delete",
        "tags": [
          "Campaigns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Campaign id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true
                }
              }
            }
          },
          "400": {
            "description": "CAMPAIGN_INVALID_STATE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/bulk/campaigns/{id}/send": {
      "post": {
        "operationId": "campaign-send",
        "summary": "Start sending",
        "description": "Starts a `draft` or `scheduled` campaign now. Messages are queued 3–7 seconds apart.\n\nUnlocked by: Notify. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#campaign-send",
        "tags": [
          "Campaigns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Campaign id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "containerId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "campaignId": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
                  "status": "sending",
                  "totalRecipients": 2,
                  "estimatedDuration": "1 minutes"
                }
              }
            }
          },
          "400": {
            "description": "CAMPAIGN_INVALID_STATE, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/bulk/campaigns/{id}/pause": {
      "post": {
        "operationId": "campaign-pause",
        "summary": "Pause",
        "description": "Stops the messages not sent yet. Only a `sending` campaign can pause.\n\nUnlocked by: Notify. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#campaign-pause",
        "tags": [
          "Campaigns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Campaign id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "status": "paused",
                  "jobsRemoved": 118
                }
              }
            }
          },
          "400": {
            "description": "CAMPAIGN_INVALID_STATE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/bulk/campaigns/{id}/resume": {
      "post": {
        "operationId": "campaign-resume",
        "summary": "Resume",
        "description": "Sends what a `paused` campaign had left, never from the start.\n\nUnlocked by: Notify. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#campaign-resume",
        "tags": [
          "Campaigns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Campaign id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "containerId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "status": "sending",
                  "jobsRequeued": 118
                }
              }
            }
          },
          "400": {
            "description": "CAMPAIGN_INVALID_STATE, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/bulk/campaigns/{id}/cancel": {
      "post": {
        "operationId": "campaign-cancel",
        "summary": "Cancel",
        "description": "Cancels a `scheduled` or `paused` campaign for good: status `cancelled`, the messages not sent yet are dropped (marked `failed`, error \"Campaign cancelled\"). To stop a `sending` campaign, pause it first.\n\nUnlocked by: Notify. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#campaign-cancel",
        "tags": [
          "Campaigns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Campaign id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "status": "cancelled",
                  "jobsRemoved": 0,
                  "messagesCancelled": 118
                }
              }
            }
          },
          "400": {
            "description": "CAMPAIGN_INVALID_STATE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/reminders": {
      "get": {
        "operationId": "reminder-list",
        "summary": "List reminders",
        "description": "Upcoming ones first (soonest first), then the others (latest change first).\n\nUnlocked by: Notify. Account key only.\n\nDocs: https://wahasend.com/docs#reminder-list",
        "tags": [
          "Reminders"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "`scheduled`, `processing`, `done`, `failed` or `cancelled`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Part of the phone number or label (100 characters max).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Default 1.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 50, max 100.",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "total": 1,
                  "page": 1,
                  "limit": 20,
                  "reminders": [
                    {
                      "id": "a7e3c5d1-9b2f-4e6a-8c04-5d1f3b7e9a28",
                      "ownerId": "2c7d0e19-4b8a-4f63-9e21-7a5c3d9b1f08",
                      "containerId": null,
                      "label": "Rent — flat 3",
                      "phone": "+22212345678",
                      "message": "Hello {{name}}, your rent of {{amount}} is due tomorrow.",
                      "variables": {
                        "name": "Aïcha",
                        "amount": "45 000 MRU"
                      },
                      "sendAt": "2026-11-01T09:00:00.000Z",
                      "firstSendAt": "2026-10-01T09:00:00.000Z",
                      "repeat": "monthly",
                      "status": "scheduled",
                      "batchId": null,
                      "sendCount": 1,
                      "lastSentAt": "2026-10-01T09:00:03.412Z",
                      "lastMessageId": "4f0c6a1e-2b7d-4c1a-9e35-7d8f2a6b1c90",
                      "lastError": null,
                      "createdAt": "2026-09-28T14:02:11.000Z",
                      "updatedAt": "2026-10-01T09:00:03.500Z",
                      "lastMessageStatus": "read"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "reminder-create",
        "summary": "Create a reminder",
        "description": "Schedules one message, optionally repeated. `{{variables}}` in the text are filled at send time.\n\nUnlocked by: Notify. Account key only.\n\nDocs: https://wahasend.com/docs#reminder-create",
        "tags": [
          "Reminders"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 20,
                    "pattern": "^\\+?[1-9]\\d{7,19}$",
                    "description": "International phone number; spaces, dashes, dots and brackets are removed."
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096,
                    "description": "1–4096 characters, may use `{{variables}}`."
                  },
                  "sendAt": {
                    "type": "string",
                    "format": "date-time",
                    "description": "First send time, with `Z` or an offset (`2026-10-01T09:00:00+00:00`). At most 5 minutes in the past."
                  },
                  "repeat": {
                    "type": "string",
                    "enum": [
                      "none",
                      "daily",
                      "weekly",
                      "monthly"
                    ],
                    "default": "none",
                    "description": "Default `none`."
                  },
                  "label": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 255
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Your own note, up to 255 characters."
                  },
                  "variables": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string",
                      "maxLength": 1000
                    },
                    "propertyNames": {
                      "maxLength": 100
                    },
                    "description": "Up to 50 values (keys ≤ 100, values ≤ 1000 characters)."
                  },
                  "containerId": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Number to send from; `null` = your default number."
                  }
                },
                "required": [
                  "phone",
                  "message",
                  "sendAt"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "message": "Hello {{name}}, your rent of {{amount}} is due tomorrow.",
                "sendAt": "2026-10-01T09:00:00Z",
                "repeat": "monthly",
                "label": "Rent — flat 3",
                "variables": {
                  "name": "Aïcha",
                  "amount": "45 000 MRU"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "reminder": {
                    "id": "a7e3c5d1-9b2f-4e6a-8c04-5d1f3b7e9a28",
                    "phone": "+22212345678",
                    "sendAt": "2026-10-01T09:00:00.000Z",
                    "repeat": "monthly",
                    "status": "scheduled",
                    "…": "…"
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/reminders/import": {
      "post": {
        "operationId": "reminder-import",
        "summary": "Import many",
        "description": "One message template for up to 5000 rows (phone + time each). Rows in the past are skipped and listed, not refused.\n\nUnlocked by: Notify. Account key only.\n\nDocs: https://wahasend.com/docs#reminder-import",
        "tags": [
          "Reminders"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096,
                    "description": "1–4096 characters, may use `{{variables}}`."
                  },
                  "repeat": {
                    "type": "string",
                    "enum": [
                      "none",
                      "daily",
                      "weekly",
                      "monthly"
                    ],
                    "default": "none",
                    "description": "Default `none`."
                  },
                  "containerId": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Number to send from."
                  },
                  "rows": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "phone": {
                          "type": "string",
                          "minLength": 8,
                          "maxLength": 20,
                          "pattern": "^\\+?[1-9]\\d{7,19}$"
                        },
                        "sendAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "label": {
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 255
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "variables": {
                          "type": "object",
                          "additionalProperties": {
                            "type": "string",
                            "maxLength": 1000
                          },
                          "propertyNames": {
                            "maxLength": 100
                          }
                        }
                      },
                      "required": [
                        "phone",
                        "sendAt"
                      ],
                      "additionalProperties": false
                    },
                    "minItems": 1,
                    "maxItems": 5000,
                    "description": "1–5000 rows."
                  }
                },
                "required": [
                  "message",
                  "rows"
                ],
                "additionalProperties": false
              },
              "example": {
                "message": "Hello {{name}}, see you at {{time}}.",
                "rows": [
                  {
                    "phone": "+22212345678",
                    "sendAt": "2026-10-02T08:00:00Z",
                    "variables": {
                      "name": "Aïcha",
                      "time": "10:00"
                    }
                  },
                  {
                    "phone": "+22287654321",
                    "sendAt": "2026-10-02T08:00:00Z",
                    "variables": {
                      "name": "Moussa",
                      "time": "11:30"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "created": 2,
                  "batchId": "e5c1a9f3-2d7b-4b8e-a6f0-8c3d1e5b9a72",
                  "skipped": []
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/reminders/{id}": {
      "put": {
        "operationId": "reminder-update",
        "summary": "Edit a reminder",
        "description": "Any field of create. A new `sendAt` re-arms a done, failed or cancelled reminder.\n\nUnlocked by: Notify. Account key only.\n\nDocs: https://wahasend.com/docs#reminder-update",
        "tags": [
          "Reminders"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Reminder id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 20,
                    "pattern": "^\\+?[1-9]\\d{7,19}$",
                    "description": "International phone number."
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096,
                    "description": "1–4096 characters."
                  },
                  "sendAt": {
                    "type": "string",
                    "format": "date-time",
                    "description": "New time; re-arms the reminder."
                  },
                  "repeat": {
                    "type": "string",
                    "enum": [
                      "none",
                      "daily",
                      "weekly",
                      "monthly"
                    ],
                    "description": "New repetition."
                  },
                  "label": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 255
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Up to 255 characters."
                  },
                  "variables": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string",
                      "maxLength": 1000
                    },
                    "propertyNames": {
                      "maxLength": 100
                    },
                    "description": "Replaces the values."
                  },
                  "containerId": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Number to send from."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "sendAt": "2026-10-03T09:00:00Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "reminder": {
                    "id": "a7e3c5d1-9b2f-4e6a-8c04-5d1f3b7e9a28",
                    "sendAt": "2026-10-03T09:00:00.000Z",
                    "status": "scheduled",
                    "…": "…"
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, FORBIDDEN_ACTION",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "reminder-delete",
        "summary": "Delete",
        "description": "Removes the reminder for good.\n\nUnlocked by: Notify. Account key only.\n\nDocs: https://wahasend.com/docs#reminder-delete",
        "tags": [
          "Reminders"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Reminder id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/reminders/{id}/cancel": {
      "post": {
        "operationId": "reminder-cancel",
        "summary": "Cancel",
        "description": "Stops a `scheduled` reminder (it stays in the list as `cancelled`).\n\nUnlocked by: Notify. Account key only.\n\nDocs: https://wahasend.com/docs#reminder-cancel",
        "tags": [
          "Reminders"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Reminder id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "reminder": {
                    "id": "a7e3c5d1-9b2f-4e6a-8c04-5d1f3b7e9a28",
                    "status": "cancelled",
                    "…": "…"
                  }
                }
              }
            }
          },
          "400": {
            "description": "FORBIDDEN_ACTION",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/otp/send": {
      "post": {
        "operationId": "otp-send",
        "summary": "Send a code",
        "description": "Generates a code and sends it right away (no queue). Keep `requestId` for the check.\n\nLimits, so nobody can flood a phone through your app (see [OTP limits](https://wahasend.com/docs/errors.md#otp-limits)): to one phone, one code every 30 seconds, 3 per 10 minutes and 10 per 24 hours; 60 codes a minute for your whole organization. Over a limit: 429 `OTP_RATE_LIMITED` with `Retry-After` and `details` `{ scope: \"phone\" | \"organization\", reason: \"cooldown\" | \"window\" | \"day\" | \"organization\", limit, retryAfterSeconds }`. A code counts when it is sent, even if WhatsApp then refuses it.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#otp-send",
        "tags": [
          "One-time codes (OTP)"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 20,
                    "pattern": "^\\+?[1-9]\\d{7,19}$",
                    "description": "International phone number, 8–20 characters (`+22212345678`). `@lid` ids are not accepted here."
                  },
                  "template": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Your text, up to 500 characters. Must contain `{{code}}` (else 400 `OTP_TEMPLATE_MISSING_CODE`): every `{{code}}` becomes the code and every `{{expiry}}` the minutes. Default: \"Your verification code is: *{{code}}* …\"."
                  },
                  "length": {
                    "type": "integer",
                    "minimum": 4,
                    "maximum": 8,
                    "description": "Digits, 4–8. Default 6."
                  }
                },
                "required": [
                  "phone"
                ],
                "additionalProperties": false
              },
              "example": {
                "phone": "+22212345678",
                "template": "Your Kaba Shop code: {{code}}. It expires in {{expiry}} minutes.",
                "length": 6
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "requestId": "0b8e4d2a-7c1f-4a95-b3e6-9d2c5f8a1e47",
                  "phone": "+22212345678",
                  "expiresAt": "2026-09-30T10:05:00.000Z",
                  "expiresInSeconds": 300
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR, OTP_TEMPLATE_MISSING_CODE, NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "OTP_RATE_LIMITED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/otp/verify": {
      "post": {
        "operationId": "otp-verify",
        "summary": "Check a code",
        "description": "Answers `verified: true` once. A wrong code uses one of the 3 tries.\n\nA wrong code answers 400 `OTP_INVALID_CODE` with `details.attemptsRemaining`.\n\nUnlocked by: Developer. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#otp-verify",
        "tags": [
          "One-time codes (OTP)"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "requestId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "From the send."
                  },
                  "code": {
                    "type": "string",
                    "minLength": 4,
                    "maxLength": 8,
                    "description": "What the person typed, 4–8 characters."
                  }
                },
                "required": [
                  "requestId",
                  "code"
                ],
                "additionalProperties": false
              },
              "example": {
                "requestId": "0b8e4d2a-7c1f-4a95-b3e6-9d2c5f8a1e47",
                "code": "482913"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "verified": true,
                  "phone": "+22212345678"
                }
              }
            }
          },
          "400": {
            "description": "OTP_INVALID_CODE, OTP_ALREADY_VERIFIED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "OTP_EXPIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "OTP_MAX_ATTEMPTS",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/chats": {
      "get": {
        "operationId": "chats-list",
        "summary": "List conversations",
        "description": "Newest first, with the last message and the unread count.\n\nA chat known only by its WhatsApp id has `phone: \"…@lid\"`; when both are known, `lid` is added. A last message with a file adds `lastAttachment`, e.g. `\"PDF · invoice.pdf · 240 KB\"`.\n\nUnlocked by: Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#chats-list",
        "tags": [
          "Chats and contacts"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 50, at most 200 conversations (values up to 500 are accepted and give 200).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Part of a phone number or name.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "containerId",
            "in": "query",
            "required": false,
            "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "chats": [
                    {
                      "phone": "22212345678",
                      "name": "Aïcha",
                      "lastMessage": "Merci, à demain",
                      "lastDirection": "in",
                      "lastAt": "2026-09-30T10:41:07.000Z",
                      "unread": 1
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/chats/{phone}": {
      "get": {
        "operationId": "chats-thread",
        "summary": "Read a conversation",
        "description": "The last messages with one person, oldest first. Sent messages carry their delivery `status`.\n\nUnlocked by: Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#chats-thread",
        "tags": [
          "Chats and contacts"
        ],
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "description": "Phone digits (with or without `+`) or the `@lid` id, URL-encoded.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 50, at most 500.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "containerId",
            "in": "query",
            "required": false,
            "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "phone": "22212345678",
                  "name": "Aïcha",
                  "messages": [
                    {
                      "id": "4f0c6a1e-2b7d-4c1a-9e35-7d8f2a6b1c90",
                      "direction": "out",
                      "text": "Your order #1042 is ready for pickup.",
                      "at": "2026-09-30T10:30:12.000Z",
                      "status": "read"
                    },
                    {
                      "id": "9a3e1b77-0c52-4f8e-b1d4-2e6c9f0a7b13",
                      "direction": "in",
                      "text": "Merci, à demain",
                      "at": "2026-09-30T10:41:07.000Z",
                      "type": "chat"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/chats/unread": {
      "get": {
        "operationId": "chats-unread",
        "summary": "Unread messages",
        "description": "Received messages nobody has marked read, oldest first. Does not mark them.\n\nUnlocked by: Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#chats-unread",
        "tags": [
          "Chats and contacts"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 100, at most 500.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "containerId",
            "in": "query",
            "required": false,
            "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "messages": [
                    {
                      "id": "9a3e1b77-0c52-4f8e-b1d4-2e6c9f0a7b13",
                      "phone": "22212345678",
                      "name": "Aïcha",
                      "text": "Merci, à demain",
                      "type": "chat",
                      "at": "2026-09-30T10:41:07.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/chats/unread/ack": {
      "post": {
        "operationId": "chats-ack",
        "summary": "Mark messages read",
        "description": "Marks the given received messages as read in WahaSend (the contact sees no blue ticks). A per-number key marks only its own number's messages.\n\nUnlocked by: Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#chats-ack",
        "tags": [
          "Chats and contacts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1,
                    "maxItems": 500,
                    "description": "1–500 message ids from the unread list."
                  }
                },
                "required": [
                  "ids"
                ],
                "additionalProperties": false
              },
              "example": {
                "ids": [
                  "9a3e1b77-0c52-4f8e-b1d4-2e6c9f0a7b13"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "marked": 1
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/chats/{phone}/read": {
      "post": {
        "operationId": "chats-read",
        "summary": "Mark a conversation read",
        "description": "Marks everything received from this person as read (with a per-number key: on its number only).\n\nUnlocked by: Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#chats-read",
        "tags": [
          "Chats and contacts"
        ],
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "description": "Phone digits or `@lid` id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "marked": 3
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/contacts": {
      "get": {
        "operationId": "contacts-search",
        "summary": "Find contacts",
        "description": "Searches the phone's contacts by saved name, WhatsApp name or part of the number.\n\nUnlocked by: Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#contacts-search",
        "tags": [
          "Chats and contacts"
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": true,
            "description": "1–100 characters.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 10, at most 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "contacts": [
                    {
                      "id": "5e1b7c3a-9d2f-4a86-b0e4-1c7f9a3d5b62",
                      "name": "Aïcha",
                      "phone": "22212345678",
                      "lid": "104937261508834@lid",
                      "saved": true,
                      "optedOut": false
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/contacts/count": {
      "get": {
        "operationId": "contacts-count",
        "summary": "Count contacts",
        "description": "How many contacts are known, and when the phone's recent history was last imported.\n\nUnlocked by: Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#contacts-count",
        "tags": [
          "Chats and contacts"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "count": 312,
                  "historyImportedAt": "2026-09-29T18:03:55.000Z",
                  "importing": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/contacts/sync": {
      "post": {
        "operationId": "contacts-sync",
        "summary": "Update from the phone",
        "description": "Re-reads the address book now and imports recent chats in the background. The number must be connected.\n\nUnlocked by: Connect. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#contacts-sync",
        "tags": [
          "Chats and contacts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "containerId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "contacts": 312,
                  "saved": 240,
                  "lidsLinked": 118,
                  "messagesLinked": 6,
                  "importing": true
                }
              }
            }
          },
          "400": {
            "description": "NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_SESSION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/session/list": {
      "get": {
        "operationId": "session-list",
        "summary": "List your numbers",
        "description": "Every number of the organization with its live state. `id` is the `containerId` other calls take.\n\nWith Notify, Assistant or Shop only, there is no limit: `maxSessions` is `null` and `canCreate` is `true`. With Developer or Connect active, `maxSessions` is the 3 numbers included plus the extra numbers bought (`allowance.included` + `allowance.extra`, `allowance.capped: true`). Without an active product `maxSessions` is `0`.\n\n`allowance.over` counts the numbers above the allowance (added before, or extra numbers that ended): they all keep working, and `canCreate` stays `false` until you buy extra numbers or remove some. A new number past the allowance answers 403 `NUMBER_LIMIT_REACHED` with `details: {max, used, included, extra, capped}`.\n\nThis answer (and the other number routes) has no `success` field.\n\nUnlocked by: every product. Account key only.\n\nDocs: https://wahasend.com/docs#session-list",
        "tags": [
          "WhatsApp numbers"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "sessions": [
                    {
                      "id": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64",
                      "instanceName": "waha-pool-1",
                      "label": "Shop",
                      "phoneNumber": "22212345678",
                      "status": "WORKING",
                      "isDefault": true,
                      "connected": true,
                      "me": {
                        "id": "22212345678@c.us",
                        "pushName": "Kaba Shop"
                      },
                      "hasApiKey": true,
                      "apiKeyPreview": "waha_V1StG...",
                      "createdAt": "2026-09-01T12:00:00.000Z"
                    }
                  ],
                  "maxSessions": 3,
                  "usedSessions": 1,
                  "canCreate": true,
                  "allowance": {
                    "capped": true,
                    "included": 3,
                    "extra": 0,
                    "extraExpiresAt": null,
                    "used": 1,
                    "max": 3,
                    "over": 0
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/session/send-group": {
      "get": {
        "operationId": "session-send-group",
        "summary": "Several numbers: the setting",
        "description": "Whether sends that name no number go through a group of your numbers, and how. Off by default. Owner and admins. See [Several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers).\n\nUnlocked by: every product. Account key only.\n\nDocs: https://wahasend.com/docs#session-send-group",
        "tags": [
          "WhatsApp numbers"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "sendGroup": {
                    "enabled": true,
                    "containerIds": [
                      "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64",
                      "5d1e8a2c-7b3f-4c69-a0d4-2e9f1b7c6a53"
                    ],
                    "mode": "backup",
                    "sticky": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "operationId": "session-send-group-update",
        "summary": "Several numbers: change it",
        "description": "Any of the fields; the others stay. Signed-in owner or admin only (not an API key); each change is recorded in the activity log.\n\nUnlocked by: every product. Account key only.\n\nDocs: https://wahasend.com/docs#session-send-group-update",
        "tags": [
          "WhatsApp numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean",
                    "description": "Turn sending through several numbers on or off."
                  },
                  "containerIds": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "maxItems": 20,
                    "description": "The group's numbers, in order (up to 20, your own). Needed when on."
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "backup",
                      "share"
                    ],
                    "description": "`backup` (default): the default number, the next one when it is down. `share`: spread over the group."
                  },
                  "sticky": {
                    "type": "boolean",
                    "description": "Same contact, same number (default `true`)."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "enabled": true,
                "containerIds": [
                  "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64",
                  "5d1e8a2c-7b3f-4c69-a0d4-2e9f1b7c6a53"
                ],
                "mode": "backup",
                "sticky": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "sendGroup": {
                    "enabled": true,
                    "containerIds": [
                      "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64",
                      "5d1e8a2c-7b3f-4c69-a0d4-2e9f1b7c6a53"
                    ],
                    "mode": "backup",
                    "sticky": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "USER_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/session/status": {
      "get": {
        "operationId": "session-status",
        "summary": "Connection state",
        "description": "`status` is `WORKING` when the number can send; `action` says what to do otherwise.\n\nOther states: `SCAN_QR_CODE` (link it), `STARTING`, `STOPPED`, `FAILED`, `UNREACHABLE`.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-status",
        "tags": [
          "WhatsApp numbers"
        ],
        "parameters": [
          {
            "name": "containerId",
            "in": "query",
            "required": false,
            "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "session": "n6d2b9c1e8f4a4e37",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64",
                  "status": "WORKING",
                  "connected": true,
                  "me": {
                    "id": "22212345678@c.us",
                    "pushName": "Kaba Shop"
                  },
                  "engine": "GOWS",
                  "manager": {
                    "retryCount": 0,
                    "maxRetries": 5,
                    "queuesPaused": false,
                    "lastHealthy": "2026-09-30T10:40:00.000Z",
                    "connectedSince": "2026-09-28T07:12:00.000Z",
                    "uptime": "2d 3h",
                    "totalRecoveries": 1,
                    "totalFailures": 1,
                    "lastError": null,
                    "lastErrorAt": null
                  },
                  "action": {
                    "type": "connected",
                    "message": "Session is connected and operational. All messaging features are available.",
                    "canLogout": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/session/qr": {
      "get": {
        "operationId": "session-qr",
        "summary": "QR code to link",
        "description": "While the state is `SCAN_QR_CODE`: a PNG to scan in WhatsApp → Settings → Linked devices → Link a device. It changes about every minute.\n\nAlready linked: `{ \"status\": \"already_connected\" }`. Another state: `{ \"status\": \"STARTING\", \"message\", \"hint\" }`.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-qr",
        "tags": [
          "WhatsApp numbers"
        ],
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "`raw` returns the QR text instead of an image.",
            "schema": {
              "type": "string",
              "enum": [
                "raw"
              ]
            }
          },
          {
            "name": "containerId",
            "in": "query",
            "required": false,
            "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "status": "SCAN_QR_CODE",
                  "qr": {
                    "image": "data:image/png;base64,iVBORw0KGgo…",
                    "expiresInSeconds": 60,
                    "message": "Scan this QR code with your WhatsApp app. Open WhatsApp > Settings > Linked Devices > Link a Device."
                  }
                }
              }
            }
          },
          "400": {
            "description": "NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "WAHA_UNREACHABLE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/session/pair": {
      "post": {
        "operationId": "session-pair",
        "summary": "Pairing code (no QR)",
        "description": "Gets an 8-character code to type in WhatsApp → Linked devices → Link with phone number instead. Handy when the QR is on the same phone.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-pair",
        "tags": [
          "WhatsApp numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "description": "The number being linked, international format."
                  },
                  "containerId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number."
                  }
                },
                "required": [
                  "phone"
                ]
              },
              "example": {
                "phone": "+22212345678"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "status": "code_sent",
                  "code": "ABCD-1234",
                  "message": "A pairing code has been generated. Enter it in your WhatsApp app: Settings > Linked Devices > Link a Device > Link with phone number instead."
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "WAHA_UNREACHABLE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/session/start": {
      "post": {
        "operationId": "session-start",
        "summary": "Start",
        "description": "Starts a stopped number. Then fetch the QR or a pairing code if it asks for one.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-start",
        "tags": [
          "WhatsApp numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "containerId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "status": "starting",
                  "message": "Session is starting. Use GET /api/v1/session/qr to retrieve the QR code once ready, or POST /api/v1/session/pair for a pairing code."
                }
              }
            }
          },
          "400": {
            "description": "NO_SESSION_CONFIGURED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/session/reconnect": {
      "post": {
        "operationId": "session-reconnect",
        "summary": "Reconnect",
        "description": "Restarts the connection of a number that is stuck. The link to the phone is kept.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-reconnect",
        "tags": [
          "WhatsApp numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "containerId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Restart initiated. Waiting for session to connect..."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/session/logout": {
      "post": {
        "operationId": "session-logout",
        "summary": "Unlink",
        "description": "Logs the number out of WhatsApp. Linking it again needs a new QR scan or pairing code.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-logout",
        "tags": [
          "WhatsApp numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "containerId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "status": "logged_out",
                  "message": "WhatsApp session has been disconnected. You will need to scan a new QR code to reconnect."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/session/history": {
      "get": {
        "operationId": "session-history",
        "summary": "Connection history",
        "description": "Latest state changes of the number, newest first.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-history",
        "tags": [
          "WhatsApp numbers"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 20, at most 100.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "containerId",
            "in": "query",
            "required": false,
            "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "session": "n6d2b9c1e8f4a4e37",
                  "events": [
                    {
                      "id": "b3f1…",
                      "status": "WORKING",
                      "previousStatus": "STARTING",
                      "reason": null,
                      "autoRecovery": false,
                      "metadata": null,
                      "timestamp": "2026-09-28T07:12:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/session/profile": {
      "get": {
        "operationId": "session-profile-get",
        "summary": "Read the profile",
        "description": "The WhatsApp name, \"about\" text and picture of the number.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-profile-get",
        "tags": [
          "WhatsApp numbers"
        ],
        "parameters": [
          {
            "name": "containerId",
            "in": "query",
            "required": false,
            "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "session": "n6d2b9c1e8f4a4e37",
                  "profile": {
                    "id": "22212345678@c.us",
                    "name": "Kaba Shop",
                    "status": "Open 9:00–18:00",
                    "picture": "https://pps.whatsapp.net/…"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "session-profile-update",
        "summary": "Change the profile",
        "description": "Any of name, about text and picture. Each is tried on its own; `failed` lists what WhatsApp refused.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-profile-update",
        "tags": [
          "WhatsApp numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 25,
                    "description": "1–25 characters."
                  },
                  "status": {
                    "type": "string",
                    "maxLength": 139,
                    "description": "\"About\" text, up to 139 characters."
                  },
                  "pictureUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "Public link to a square image."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "name": "Kaba Shop",
                "status": "Open 9:00–18:00"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "updated": {
                    "name": "updated",
                    "status": "updated"
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/session/profile/picture": {
      "delete": {
        "operationId": "session-profile-picture-delete",
        "summary": "Remove the picture",
        "description": "Removes the profile picture.\n\nUnlocked by: every product. A per-number key may call it.\n\nDocs: https://wahasend.com/docs#session-profile-picture-delete",
        "tags": [
          "WhatsApp numbers"
        ],
        "parameters": [
          {
            "name": "containerId",
            "in": "query",
            "required": false,
            "description": "Which of your WhatsApp numbers to use; it always wins. Default: your default number (else any connected one), or a number of the group when [several numbers](https://wahasend.com/docs/phone-numbers.md#several-numbers) is on. Ignored with a per-number key, which always uses its own number.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "status": "deleted",
                  "message": "Profile picture removed."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "WAHA_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/me": {
      "get": {
        "operationId": "me",
        "summary": "Your account",
        "description": "The organization, its active products and features, and whether a key is set. A quick way to test a key.\n\nUnlocked by: every product. Account key only.\n\nDocs: https://wahasend.com/docs#me",
        "tags": [
          "Account, history and keys"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "id": "2c7d0e19-4b8a-4f63-9e21-7a5c3d9b1f08",
                  "name": "Aminetou Sall",
                  "email": "aminetou@example.com",
                  "memberRole": "admin",
                  "organization": {
                    "id": "2c7d0e19-4b8a-4f63-9e21-7a5c3d9b1f08",
                    "name": "Kaba Shop",
                    "requireTwoFactor": false
                  },
                  "products": [
                    "developer"
                  ],
                  "features": [
                    "send",
                    "batch",
                    "api",
                    "otp",
                    "media",
                    "webhooks"
                  ],
                  "maxNumbers": null,
                  "webhookUrl": "https://example.com/hooks/wahasend",
                  "hasApiKey": true,
                  "apiKeyPreview": "3f9c1a7b2e4d***",
                  "…": "…"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/messages": {
      "get": {
        "operationId": "messages",
        "summary": "Message history",
        "description": "Messages sent by text sends, batches, campaigns, OTP, reminders and assistants, newest first.\n\nOTP messages show `[OTP MESSAGE]` instead of the code. Media sends appear with their caption or a label such as `[image] https://…`.\n\n`wahaMessageId` is WhatsApp's id once the message is sent (null before); `containerId` is the number it went from (null on older rows).\n\nUnlocked by: every product. Account key only.\n\nDocs: https://wahasend.com/docs#messages",
        "tags": [
          "Account, history and keys"
        ],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filter by kind.",
            "schema": {
              "type": "string",
              "enum": [
                "alert",
                "bulk",
                "otp"
              ]
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "`queued`, `sending`, `sent`, `delivered`, `read` or `failed`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Part of the recipient or text.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Default 1.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 50, at most 100.",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "total": 1,
                  "page": 1,
                  "limit": 20,
                  "messages": [
                    {
                      "id": "4f0c6a1e-2b7d-4c1a-9e35-7d8f2a6b1c90",
                      "type": "alert",
                      "recipient": "22212345678",
                      "content": "Your order #1042 is ready for pickup.",
                      "status": "failed",
                      "priority": "normal",
                      "error": "Message delivery failed (ACK 0)",
                      "sentAt": null,
                      "deliveredAt": null,
                      "createdAt": "2026-09-30T10:30:10.000Z",
                      "wahaMessageId": "true_22212345678@c.us_3EB0C767D26A1D2E5A8F",
                      "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/stats": {
      "get": {
        "operationId": "stats",
        "summary": "Counts",
        "description": "Totals of all messages, by status and kind, plus the last 24 hours and 7 days.\n\nUnlocked by: every product. Account key only.\n\nDocs: https://wahasend.com/docs#stats",
        "tags": [
          "Account, history and keys"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "totalMessages": 1247,
                  "sent": 30,
                  "delivered": 1150,
                  "failed": 47,
                  "alerts": 900,
                  "bulk": 320,
                  "otp": 27,
                  "last24h": 58,
                  "last7d": 412
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/me/regenerate-key": {
      "post": {
        "operationId": "regenerate-key",
        "summary": "Replace the account key",
        "description": "Issues a new account key; the old one stops working at once. `POST /me/generate-key` does the same the first time (409 `CONFLICT` once a key exists).\n\nUnlocked by: every product. Account key only.\n\nDocs: https://wahasend.com/docs#regenerate-key",
        "tags": [
          "Account, history and keys"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "apiKey": "wn_8c1f…64 hex characters…",
                  "warning": "Save this new API key now. Your old key has been invalidated."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/session/{containerId}/regenerate-key": {
      "post": {
        "operationId": "regenerate-number-key",
        "summary": "Replace a per-number key",
        "description": "New key for one number; the old one stops working. `POST /session/:containerId/generate-key` creates the first one.\n\nUnlocked by: every product. Account key only.\n\nDocs: https://wahasend.com/docs#regenerate-number-key",
        "tags": [
          "Account, history and keys"
        ],
        "parameters": [
          {
            "name": "containerId",
            "in": "path",
            "required": true,
            "description": "The number, from `GET /session/list`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "apiKey": "waha_V1StGXR8_Z5jdHi6B-myT…",
                  "containerId": "6d2b9c1e-8f4a-4e37-a5c2-1b9e7d3f0a64",
                  "label": "Shop",
                  "warning": "Store this key securely. It cannot be retrieved again."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "CONTAINER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/me/webhook": {
      "get": {
        "operationId": "webhook-get",
        "summary": "Webhook URL and signing secret",
        "description": "The URL and the secret to [check signatures](https://wahasend.com/docs/webhooks.md#webhook-security) with. Owners and admins only.\n\n`signingSecret` is null when no URL was ever set (or on a server without encryption set up: deliveries are then unsigned).\n\nUnlocked by: Assistant, Shop, Developer. Account key only.\n\nDocs: https://wahasend.com/docs#webhook-get",
        "tags": [
          "Webhook address and signing secret"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "webhookUrl": "https://example.com/hooks/wahasend-7Qe2xLp9",
                  "signingSecret": "whsec_5f0c…64 hex characters…"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED, ROLE_FORBIDDEN",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "operationId": "webhook-set",
        "summary": "Set or clear the webhook URL",
        "description": "One URL per organization. `null` stops the events. The first URL also creates the signing secret, returned once here as `signingSecret` (read it again with `GET /me/webhook`).\n\nUnlocked by: Assistant, Shop, Developer. Account key only.\n\nDocs: https://wahasend.com/docs#webhook-set",
        "tags": [
          "Webhook address and signing secret"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "webhookUrl": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uri",
                        "maxLength": 2000
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Public http(s) address, up to 2000 characters. Private and local addresses are refused."
                  }
                },
                "required": [
                  "webhookUrl"
                ],
                "additionalProperties": false
              },
              "example": {
                "webhookUrl": "https://example.com/hooks/wahasend-7Qe2xLp9"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "webhookUrl": "https://example.com/hooks/wahasend-7Qe2xLp9",
                  "signingSecret": "whsec_5f0c…64 hex characters…"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/me/webhook/regenerate-secret": {
      "post": {
        "operationId": "webhook-secret-regenerate",
        "summary": "Replace the signing secret",
        "description": "A new secret; deliveries are signed with it at once and the old one no longer verifies. Update your receiver right after.\n\nUnlocked by: Assistant, Shop, Developer. Account key only.\n\nDocs: https://wahasend.com/docs#webhook-secret-regenerate",
        "tags": [
          "Webhook address and signing secret"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "signingSecret": "whsec_91ab…64 hex characters…",
                  "warning": "Update your receiver with this secret now. Deliveries are signed with it from now on."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "PRODUCT_REQUIRED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "WEBHOOK_SIGNING_UNAVAILABLE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Account or per-number key (dashboard → For developers). `Authorization: Bearer <key>` also works on the MCP endpoint."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "const": false
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "requestId"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "VALIDATION_ERROR",
                  "INVALID_JSON",
                  "INVALID_ID",
                  "PAYLOAD_TOO_LARGE",
                  "FILE_TOO_LARGE",
                  "ROUTE_NOT_FOUND",
                  "NOT_FOUND",
                  "CONFLICT",
                  "REFERENCE_ERROR",
                  "IN_USE",
                  "CONSTRAINT_VIOLATION",
                  "FORBIDDEN_ACTION",
                  "RATE_LIMIT",
                  "RATE_LIMITED",
                  "AUTH_ERROR",
                  "TOO_MANY_LOGIN_ATTEMPTS",
                  "ACCOUNT_DEACTIVATED",
                  "OAUTH_TOKEN_SCOPE",
                  "OAUTH_REQUEST_INVALID",
                  "NUMBER_KEY_SCOPE",
                  "USER_REQUIRED",
                  "WRONG_PASSWORD",
                  "NO_PASSWORD_SET",
                  "INVALID_LINK",
                  "SIGNUP_DISABLED",
                  "TWO_FACTOR_REQUIRED",
                  "TWO_FACTOR_CODE_INVALID",
                  "TWO_FACTOR_CHALLENGE_EXPIRED",
                  "TWO_FACTOR_SETUP_EXPIRED",
                  "TWO_FACTOR_ALREADY_ENABLED",
                  "TWO_FACTOR_NOT_ENABLED",
                  "TWO_FACTOR_OWNER_FIRST",
                  "TWO_FACTOR_UNAVAILABLE",
                  "COUNTRY_LOCKED",
                  "PRODUCT_REQUIRED",
                  "NO_ACTIVE_PRODUCT",
                  "ADMIN_ONLY",
                  "ROLE_FORBIDDEN",
                  "ADMIN_CANNOT_DELETE",
                  "INVITE_INVALID",
                  "INVITE_EMAIL_MISMATCH",
                  "ALREADY_MEMBER",
                  "TEAM_FULL",
                  "OWNER_ROLE_FIXED",
                  "CANNOT_REMOVE_OWNER",
                  "OWNER_CANNOT_LEAVE",
                  "LAST_ORGANIZATION",
                  "NOT_OWNER",
                  "ALREADY_OWNER",
                  "OWNS_ORGANIZATION",
                  "USE_LEAVE",
                  "TOO_MANY_ORGANIZATIONS",
                  "NO_SESSION_CONFIGURED",
                  "SESSION_NOT_CONNECTED",
                  "CONTAINER_NOT_FOUND",
                  "NUMBER_LIMIT_REACHED",
                  "PORT_EXHAUSTED",
                  "NUMBER_NOT_ON_WHATSAPP",
                  "NO_VALID_NUMBERS",
                  "NUMBER_ON_OTHER_ASSISTANT",
                  "SECRETS_KEY_MISSING",
                  "NUMBER_VALIDATION_UNAVAILABLE",
                  "OTP_EXPIRED",
                  "OTP_ALREADY_VERIFIED",
                  "OTP_MAX_ATTEMPTS",
                  "OTP_INVALID_CODE",
                  "OTP_RATE_LIMITED",
                  "OTP_TEMPLATE_MISSING_CODE",
                  "MESSAGE_NOT_FOUND",
                  "MESSAGE_NOT_SENT",
                  "MESSAGE_WRONG_NUMBER",
                  "CAMPAIGN_INVALID_STATE",
                  "STAFF_PHONE_LIMIT",
                  "STAFF_PHONE_IS_BUSINESS",
                  "WEBHOOK_SIGNING_UNAVAILABLE",
                  "ATTACHMENT_NOT_FOUND",
                  "ATTACHMENT_EXPIRED",
                  "ATTACHMENT_TOO_LARGE",
                  "ATTACHMENT_UNSUPPORTED",
                  "TRANSCRIPTION_UNAVAILABLE",
                  "SEND_FILE_TOO_LARGE",
                  "SEND_FILE_TYPE_NOT_ALLOWED",
                  "SEND_FILE_URL_UNREACHABLE",
                  "WAHA_ERROR",
                  "WAHA_SESSION_ERROR",
                  "WAHA_UNREACHABLE",
                  "UPSTREAM_TIMEOUT",
                  "AI_UNAVAILABLE",
                  "AI_BUSY",
                  "SERVICE_BUSY",
                  "AI_QUOTA_EXCEEDED",
                  "TRIAL_LIMIT_REACHED",
                  "PADDLE_NOT_CONFIGURED",
                  "PADDLE_NO_SUBSCRIPTION",
                  "PADDLE_UNAVAILABLE",
                  "PADDLE_SIGNATURE_INVALID",
                  "PADDLE_CHANGE_REFUSED",
                  "PADDLE_NOTHING_TO_RESUME",
                  "PADDLE_PERIOD_UNAVAILABLE",
                  "PADDLE_SAME_PERIOD",
                  "INVOICE_NOT_AVAILABLE",
                  "INTERNAL_ERROR"
                ]
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object"
              },
              "issues": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "requestId": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or wrong API key (AUTH_ERROR)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests (RATE_LIMITED); wait for Retry-After seconds",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
