{
  "openapi": "3.1.0",
  "info": {
    "title": "WAIX API",
    "version": "1.0.0",
    "description": "WhatsApp API: отправка через устойчивую очередь, статусы доставки, шаблоны, медиа, профиль и вебхуки. Для отправки требуется оплаченная подписка WAIX. Сообщения с вашего номера оплачиваются в Meta отдельно. OTP API использует отдельный месячный пакет отправок с номера WAIX, с sandbox для разработки. Текущая версия — v1; базовый адрес закреплён за этой версией. Несовместимые изменения выходят в новой версии URL, без автоматического переключения клиентов. Заголовок X-WAIX-API-Version содержит v1."
  },
  "servers": [
    {
      "url": "https://waix.kz/api/v1",
      "description": "Версия v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/messages": {
      "post": {
        "summary": "Поставить сообщение в очередь",
        "operationId": "createMessage",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "UUID, уникальный для логической отправки.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMessage"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Сообщение сохранено локально и поставлено в очередь.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QueuedMessageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "402": {
            "description": "Нет оплаченного доступа к API."
          }
        },
        "x-required-scopes": [
          "messages:write"
        ]
      },
      "get": {
        "summary": "Журнал сообщений",
        "operationId": "getMessages",
        "x-required-scopes": [
          "messages:read"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "description": "Сообщение: id, connection_id, to, type, body, status, direction, created_at, failure_category."
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "next_before": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "next_before_id": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "before",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "before_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "connection_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "queued",
                "processing",
                "sent",
                "delivered",
                "read",
                "received",
                "failed",
                "outcome_unknown"
              ]
            }
          }
        ]
      }
    },
    "/messages/{id}": {
      "get": {
        "summary": "Получить сообщение и журнал попыток",
        "operationId": "getMessage",
        "parameters": [
          {
            "$ref": "#/components/parameters/MessageId"
          }
        ],
        "responses": {
          "200": {
            "description": "Текущее состояние сообщения.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-required-scopes": [
          "messages:read"
        ]
      }
    },
    "/messages/{id}/retry": {
      "post": {
        "summary": "Повторить неуспешное сообщение",
        "operationId": "retryMessage",
        "parameters": [
          {
            "$ref": "#/components/parameters/MessageId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm_outcome_unknown": {
                    "type": "boolean",
                    "default": false
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Новая попытка поставлена в очередь.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "402": {
            "description": "Нет оплаченного доступа к API."
          }
        },
        "x-required-scopes": [
          "messages:write"
        ]
      }
    },
    "/connections": {
      "get": {
        "summary": "Номера WhatsApp",
        "operationId": "getConnections",
        "x-required-scopes": [
          "connections:read"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        }
      }
    },
    "/connections/{id}/templates": {
      "get": {
        "summary": "Шаблоны и статусы модерации",
        "operationId": "getConnectionsIdTemplates",
        "x-required-scopes": [
          "templates:read"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      },
      "post": {
        "summary": "Создать шаблон: body с примерами либо components по формату Meta",
        "operationId": "postConnectionsIdTemplates",
        "x-required-scopes": [
          "templates:write"
        ],
        "responses": {
          "201": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "pattern": "^[a-z0-9_]+$",
                    "maxLength": 512
                  },
                  "language": {
                    "type": "string"
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "UTILITY",
                      "MARKETING",
                      "AUTHENTICATION"
                    ]
                  },
                  "body": {
                    "type": "string",
                    "maxLength": 1024
                  },
                  "variable_examples": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "components": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 10,
                    "items": {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "HEADER",
                            "BODY",
                            "FOOTER",
                            "BUTTONS",
                            "CAROUSEL",
                            "LIMITED_TIME_OFFER"
                          ]
                        }
                      },
                      "required": [
                        "type"
                      ]
                    }
                  }
                },
                "required": [
                  "name",
                  "language",
                  "category"
                ]
              }
            }
          }
        }
      }
    },
    "/connections/{id}/templates/{name}": {
      "get": {
        "summary": "Один шаблон",
        "operationId": "getConnectionsIdTemplatesName",
        "x-required-scopes": [
          "templates:read"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "language",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "patch": {
        "summary": "Изменить компоненты шаблона с повторной модерацией Meta",
        "operationId": "patchConnectionsIdTemplatesName",
        "x-required-scopes": [
          "templates:write"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "language": {
                    "type": "string"
                  },
                  "components": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 10,
                    "items": {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "HEADER",
                            "BODY",
                            "FOOTER",
                            "BUTTONS",
                            "CAROUSEL",
                            "LIMITED_TIME_OFFER"
                          ]
                        }
                      },
                      "required": [
                        "type"
                      ]
                    }
                  }
                },
                "required": [
                  "language",
                  "components"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Удалить все языковые версии шаблона",
        "operationId": "deleteConnectionsIdTemplatesName",
        "x-required-scopes": [
          "templates:write"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/connections/{id}/templates/preview": {
      "post": {
        "summary": "Предпросмотр текстовых переменных",
        "operationId": "postConnectionsIdTemplatesPreview",
        "x-required-scopes": [
          "templates:read"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "template_name": {
                    "type": "string"
                  },
                  "parameters": {
                    "type": "object",
                    "properties": {
                      "header": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "body": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "required": [
                  "template_name"
                ]
              }
            }
          }
        }
      }
    },
    "/connections/{id}/profile": {
      "get": {
        "summary": "Профиль WhatsApp Business",
        "operationId": "getConnectionsIdProfile",
        "x-required-scopes": [
          "profile:read"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      },
      "put": {
        "summary": "Обновить профиль",
        "operationId": "putConnectionsIdProfile",
        "x-required-scopes": [
          "profile:write"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "about": {
                    "type": "string",
                    "maxLength": 139
                  },
                  "address": {
                    "type": "string",
                    "maxLength": 256
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 512
                  },
                  "email": {
                    "type": "string"
                  },
                  "vertical": {
                    "type": "string"
                  },
                  "websites": {
                    "type": "array",
                    "maxItems": 2,
                    "items": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/media": {
      "get": {
        "summary": "Медиафайлы рабочего пространства",
        "operationId": "getMedia",
        "x-required-scopes": [
          "media:read"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        }
      },
      "post": {
        "summary": "Загрузить медиа (до 32 МиБ, фактический лимит зависит от типа)",
        "operationId": "postMedia",
        "x-required-scopes": [
          "media:write"
        ],
        "responses": {
          "201": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "connection_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "image",
                      "video",
                      "audio",
                      "document",
                      "sticker"
                    ]
                  },
                  "voice": {
                    "type": "string",
                    "enum": [
                      "true",
                      "false"
                    ]
                  }
                },
                "required": [
                  "connection_id",
                  "file"
                ]
              }
            }
          }
        }
      }
    },
    "/media/{id}/url": {
      "get": {
        "summary": "Временная ссылка на медиафайл",
        "operationId": "getMediaIdUrl",
        "x-required-scopes": [
          "media:read"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/media/{id}": {
      "delete": {
        "summary": "Удалить медиафайл",
        "operationId": "deleteMediaId",
        "x-required-scopes": [
          "media:write"
        ],
        "responses": {
          "204": {
            "description": "Успешный результат"
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/webhook": {
      "get": {
        "summary": "Адрес, события и последние попытки доставки",
        "operationId": "getWebhook",
        "x-required-scopes": [
          "webhooks:read"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        }
      },
      "put": {
        "summary": "Настроить вебхук; секрет возвращается только при создании",
        "operationId": "putWebhook",
        "x-required-scopes": [
          "webhooks:write"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "string",
                      "enum": [
                        "message.received",
                        "message.status.updated"
                      ]
                    }
                  },
                  "active": {
                    "type": "boolean",
                    "default": true
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Удалить вебхук",
        "operationId": "deleteWebhook",
        "x-required-scopes": [
          "webhooks:write"
        ],
        "responses": {
          "204": {
            "description": "Успешный результат"
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        }
      }
    },
    "/webhook/test": {
      "post": {
        "summary": "Отправить тестовое событие",
        "operationId": "postWebhookTest",
        "x-required-scopes": [
          "webhooks:write"
        ],
        "responses": {
          "202": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        }
      }
    },
    "/webhook/rotate-secret": {
      "post": {
        "summary": "Заменить секрет подписи",
        "operationId": "postWebhookRotateSecret",
        "x-required-scopes": [
          "webhooks:write"
        ],
        "responses": {
          "200": {
            "description": "Успешный результат",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ошибка параметров"
          },
          "401": {
            "description": "Неверный или просроченный ключ"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "404": {
            "description": "Объект не найден в вашем рабочем пространстве"
          },
          "429": {
            "description": "Превышен лимит запросов"
          }
        }
      }
    },
    "/otp/send": {
      "post": {
        "summary": "Создать и отправить код подтверждения",
        "operationId": "sendOtp",
        "description": "Нужен ключ OTP-проекта со scope otp:send. Sandbox не отправляет сообщений и возвращает test_code. Live требует оплаченного пакета для страны получателя. Код действует 60–600 секунд, не более пяти попыток проверки. Лимит резервируется при приёме заявки и возвращается при подтверждённой ошибке доставки; при неизвестном результате повторной отправки нет.",
        "x-required-scopes": [
          "otp:send"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Сохраняйте ключ при сетевых повторах одного запроса. Изменение параметров с тем же ключом вернёт 409."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "to"
                ],
                "additionalProperties": false,
                "properties": {
                  "to": {
                    "type": "string",
                    "example": "+77011234567"
                  },
                  "channel": {
                    "type": "string",
                    "enum": [
                      "whatsapp"
                    ],
                    "default": "whatsapp"
                  },
                  "ttl": {
                    "type": "integer",
                    "minimum": 60,
                    "maximum": 600,
                    "default": 300
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Заявка создана. В sandbox ответ также содержит test_code.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/OtpChallenge"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Неверный номер или параметры."
          },
          "402": {
            "description": "Нет оплаченного OTP-пакета или исчерпан лимит."
          },
          "409": {
            "description": "Отправитель не готов либо Idempotency-Key использован с другими параметрами."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "description": "Превышен лимит запросов. Повторную отправку на тот же номер можно запросить через 60 секунд; не повторяйте send при неизвестном результате без прежнего Idempotency-Key."
          },
          "200": {
            "description": "Повторный запрос: та же заявка без повторной отправки и без test_code.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/OtpChallenge"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/otp/verify": {
      "post": {
        "summary": "Проверить код один раз",
        "operationId": "verifyOtp",
        "x-required-scopes": [
          "otp:verify"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "id",
                  "code"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "code": {
                    "type": "string",
                    "pattern": "^[0-9]{6}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Код подтверждён.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/OtpChallenge"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Неверный, просроченный или уже использованный код."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "description": "Превышен лимит запросов. Повторную отправку на тот же номер можно запросить через 60 секунд; не повторяйте send при неизвестном результате без прежнего Idempotency-Key."
          }
        }
      }
    },
    "/otp/{id}": {
      "get": {
        "summary": "Проверить состояние кода и доставки",
        "operationId": "getOtp",
        "x-required-scopes": [
          "otp:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Текущее состояние OTP; секретных полей в ответе нет.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/OtpChallenge"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "description": "Превышен лимит запросов. Повторную отправку на тот же номер можно запросить через 60 секунд; не повторяйте send при неизвестном результате без прежнего Idempotency-Key."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Waix API key",
        "description": "API-ключ рабочего пространства. Нужные права указаны в x-required-scopes каждого метода."
      }
    },
    "parameters": {
      "MessageId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "Локальный ID Waix."
      }
    },
    "schemas": {
      "CommonMessageFields": {
        "type": "object",
        "required": [
          "connection_id",
          "to"
        ],
        "properties": {
          "connection_id": {
            "type": "string",
            "format": "uuid"
          },
          "to": {
            "type": "string",
            "pattern": "^\\+?[0-9]{8,16}$"
          },
          "client_message_id": {
            "type": "string",
            "maxLength": 200
          },
          "reply_to_message_id": {
            "type": "string",
            "format": "uuid"
          },
          "media_object_id": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "TextMessage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonMessageFields"
          },
          {
            "type": "object",
            "required": [
              "type",
              "text"
            ],
            "properties": {
              "type": {
                "const": "text"
              },
              "text": {
                "type": "object",
                "required": [
                  "body"
                ],
                "properties": {
                  "body": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096
                  },
                  "preview_url": {
                    "type": "boolean",
                    "default": false
                  }
                },
                "additionalProperties": false
              }
            }
          }
        ]
      },
      "LegacyTextMessage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonMessageFields"
          },
          {
            "type": "object",
            "required": [
              "body"
            ],
            "properties": {
              "body": {
                "type": "string",
                "minLength": 1,
                "maxLength": 4096
              }
            }
          }
        ]
      },
      "MediaMessage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonMessageFields"
          },
          {
            "type": "object",
            "required": [
              "type",
              "media"
            ],
            "properties": {
              "type": {
                "enum": [
                  "image",
                  "video",
                  "audio",
                  "document",
                  "sticker"
                ]
              },
              "media": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "link": {
                    "type": "string",
                    "format": "uri",
                    "pattern": "^https://"
                  },
                  "caption": {
                    "type": "string",
                    "maxLength": 1024
                  },
                  "filename": {
                    "type": "string",
                    "maxLength": 240
                  },
                  "voice": {
                    "type": "boolean"
                  }
                },
                "oneOf": [
                  {
                    "required": [
                      "id"
                    ],
                    "not": {
                      "required": [
                        "link"
                      ]
                    }
                  },
                  {
                    "required": [
                      "link"
                    ],
                    "not": {
                      "required": [
                        "id"
                      ]
                    }
                  }
                ]
              }
            }
          }
        ]
      },
      "TemplateMessage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonMessageFields"
          },
          {
            "type": "object",
            "required": [
              "type",
              "template"
            ],
            "properties": {
              "type": {
                "const": "template"
              },
              "template": {
                "type": "object",
                "required": [
                  "name",
                  "language"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 512
                  },
                  "language": {
                    "type": "object",
                    "required": [
                      "code"
                    ],
                    "properties": {
                      "code": {
                        "type": "string"
                      }
                    }
                  },
                  "components": {
                    "type": "array",
                    "maxItems": 20,
                    "items": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "InteractiveMessage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonMessageFields"
          },
          {
            "type": "object",
            "required": [
              "type",
              "interactive"
            ],
            "properties": {
              "type": {
                "const": "interactive"
              },
              "interactive": {
                "type": "object",
                "required": [
                  "type",
                  "body",
                  "action"
                ],
                "properties": {
                  "type": {
                    "enum": [
                      "button",
                      "list"
                    ]
                  },
                  "body": {
                    "type": "object",
                    "required": [
                      "text"
                    ],
                    "properties": {
                      "text": {
                        "type": "string",
                        "maxLength": 1024
                      }
                    }
                  },
                  "action": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        ]
      },
      "ReactionMessage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonMessageFields"
          },
          {
            "type": "object",
            "required": [
              "type",
              "reaction",
              "reply_to_message_id"
            ],
            "properties": {
              "type": {
                "const": "reaction"
              },
              "reaction": {
                "type": "object",
                "required": [
                  "emoji"
                ],
                "properties": {
                  "emoji": {
                    "type": "string"
                  }
                }
              }
            }
          }
        ]
      },
      "CreateMessage": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/TextMessage"
          },
          {
            "$ref": "#/components/schemas/LegacyTextMessage"
          },
          {
            "$ref": "#/components/schemas/MediaMessage"
          },
          {
            "$ref": "#/components/schemas/TemplateMessage"
          },
          {
            "$ref": "#/components/schemas/InteractiveMessage"
          },
          {
            "$ref": "#/components/schemas/ReactionMessage"
          }
        ]
      },
      "QueuedMessageResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "id",
              "status"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "const": "queued"
              }
            }
          }
        }
      },
      "Message": {
        "type": "object",
        "required": [
          "id",
          "connection_id",
          "type",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "client_message_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "connection_id": {
            "type": "string",
            "format": "uuid"
          },
          "conversation_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "to": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": "string"
          },
          "body": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "enum": [
              "queued",
              "processing",
              "accepted",
              "sent",
              "delivered",
              "read",
              "failed",
              "outcome_unknown"
            ]
          },
          "meta_message_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "failure_category": {
            "type": [
              "string",
              "null"
            ]
          },
          "attempt_count": {
            "type": "integer",
            "minimum": 0
          },
          "media_object_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "reply_to_message_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "queued_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "processing_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "accepted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "read_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "failed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "attempts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "MessageResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Message"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "request_id": {
                "type": "string"
              }
            }
          }
        }
      },
      "OtpChallenge": {
        "type": "object",
        "description": "Код и его хеш не возвращаются. test_code доступен только в первом ответе sandbox send. Повтор с тем же ключом возвращает ту же заявку без test_code.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "channel": {
            "type": "string",
            "enum": [
              "whatsapp"
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "sandbox",
              "live"
            ]
          },
          "recipient": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "sending",
              "outcome_unknown",
              "sent",
              "delivered",
              "read",
              "verified",
              "failed",
              "expired"
            ]
          },
          "attempts_remaining": {
            "type": "integer",
            "minimum": 0,
            "maximum": 5
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "test_code": {
            "type": "string",
            "pattern": "^[0-9]{6}$",
            "description": "Только для первого ответа sandbox send."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "read_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "verified_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Некорректный запрос.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Ключ отсутствует, истёк или отозван.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "У ключа нет требуемого scope.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Сообщение не найдено в организации ключа.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Конфликт idempotency или недопустимый retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ValidationError": {
        "description": "Payload не прошёл предметную проверку.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Превышен лимит запросов.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
