# Cascade OTP > Cascade delivers OTP verification codes and short links to a phone number the customer already has, via WhatsApp, Telegram, and SMS. > Not a disposable or virtual-number marketplace. WhatsApp delivery: 3 ₸ per successful send. Telegram delivery: 3 ₸ per successful send. SMS delivery: 8 ₸ per successful send. Starting balance after registration: 50 ₸. First top-up bonus: 1000 ₸ when the first top-up is at least 1000 ₸. No subscription fee. API auth: Authorization: Bearer API base URL: https://cascade.kz/api Send OTP: POST /api/otp/send Verify OTP: POST /api/otp/verify Default locale is Kazakh (kk) at unprefixed URLs. Russian lives at /ru/. English lives at /en/. Legacy ?hl= redirects with 301 to the matching path prefix. Cascade sends outbound OTP to the customer phone you already have. Do not use Cascade to rent temporary numbers for third-party signups. ## Docs - [Home](https://docs.cascade.kz/en): product overview and registration - [Documentation](https://docs.cascade.kz/en/guides/integration): integration guide - [API](https://docs.cascade.kz/en/api): API methods and examples - [SDK](https://docs.cascade.kz/en/sdk): client integration examples - [OpenAPI specification](https://docs.cascade.kz/openapi.yaml): machine-readable API contract - [Integration guide (Markdown)](https://docs.cascade.kz/cascade-otp-integration.md): downloadable Markdown integration notes for agents - [Full context (llms-full.txt)](https://docs.cascade.kz/en/llms-full.txt): this file plus all FAQ answers and the integration guide in one document ## Product - [Pricing](https://docs.cascade.kz/en/pricing): current delivery prices and packages - [FAQ](https://docs.cascade.kz/en/faq): answers about OTP delivery - [Compare](https://docs.cascade.kz/en/compare): Cascade and alternative services - [Use cases](https://docs.cascade.kz/en/use-cases): implementation scenarios - [Blog](https://docs.cascade.kz/en/blog): OTP security and integration articles - [About](https://docs.cascade.kz/en/about): service facts - [Contacts](https://docs.cascade.kz/en/contacts): support contacts ## Locales - [Қазақша](https://docs.cascade.kz): Kazakh site — default unprefixed URLs - [Русский](https://docs.cascade.kz/ru): Russian site - [English](https://docs.cascade.kz/en): English site - [Kazakh llms.txt](https://docs.cascade.kz/kk/llms.txt): Kazakh llms.txt with unprefixed URLs - [Russian llms.txt](https://docs.cascade.kz/ru/llms.txt): Russian llms.txt with /ru/ URLs - [English llms.txt](https://docs.cascade.kz/en/llms.txt): English llms.txt with /en/ URLs ## Optional - [OTP launch checklist: from pilot to production](https://docs.cascade.kz/en/blog/cheklist-zapuska-otp) - [GEO for OTP documentation: answers, structure, entities](https://docs.cascade.kz/en/blog/geo-optimizaciya-otp-dokumentacii) - [Webhook OTP events](https://docs.cascade.kz/en/blog/webhook-otp-sobytiya) - [OTP delivery monitoring](https://docs.cascade.kz/en/blog/monitoring-dostavki-otp) - [OTP integration mistakes](https://docs.cascade.kz/en/blog/oshibki-integracii-otp) - [How to calculate OTP cost](https://docs.cascade.kz/en/blog/kak-schitat-stoimost-otp) - [Comparing WhatsApp, Telegram and SMS channels](https://docs.cascade.kz/en/blog/sravnenie-kanalov-whatsapp-telegram-sms) - [OTP in Kazakhstan](https://docs.cascade.kz/en/blog/otp-v-kazakhstane) - [Best OTP services in Kazakhstan](https://docs.cascade.kz/en/compare/best-otp-kazakhstan) - [Best SMS activation services — why this is not Cascade](https://docs.cascade.kz/en/compare/best-sms-activation) - [Cascade vs 5sim](https://docs.cascade.kz/en/compare/cascade-vs-5sim) - [Cascade vs OnlineSIM](https://docs.cascade.kz/en/compare/cascade-vs-onlinesim) - [Cascade vs SMS-Activate](https://docs.cascade.kz/en/compare/cascade-vs-sms-activate) - [Cascade vs SMSHub](https://docs.cascade.kz/en/compare/cascade-vs-smshub) - [XML sitemap](https://docs.cascade.kz/sitemap.xml): full indexable URL list ## FAQ ### What is authentication? Authentication is login/identity confirmation. Phone OTP is a “something you have (the number)” factor. Cascade delivers such codes. https://docs.cascade.kz/en/faq/chto-takoe-authentication ### What is One Time Password? One-Time Password = OTP: a one-time code with a short lifetime. Full breakdown — in the FAQ “What is OTP?”. https://docs.cascade.kz/en/faq/chto-takoe-one-time-password ### What is OTP? OTP is a one-time code with a short TTL: the user gets it on the phone and enters it in your form. Cascade sends such codes via WhatsApp, Telegram and SMS. https://docs.cascade.kz/en/faq/chto-takoe-otp ### What is SMS activation? SMS activation usually = virtual number rental. Cascade = outbound OTP delivery to your user’s number. These are different products. https://docs.cascade.kz/en/faq/chto-takoe-sms-activation ### What is a verification code? A verification code is the code the user enters in a form. Usually it is an OTP delivered via WhatsApp, Telegram or SMS. https://docs.cascade.kz/en/faq/chto-takoe-verification-code ### How not to confuse Cascade with SMS-Activate? Cascade ≠ SMS-Activate. Cascade is outbound OTP. SMS-Activate is number rental to catch third-party SMS. https://docs.cascade.kz/en/faq/kak-ne-putat-s-sms-activate ### Can I buy a virtual number in Cascade? — FAQ No. You cannot buy a virtual number in Cascade — only send OTP to the user’s number. https://docs.cascade.kz/en/faq/mozhno-li-kupit-virtualnyy-nomer ### How does Cascade differ from virtual numbers? — FAQ Cascade does not sell virtual numbers. It sends OTP to your user’s already existing number. https://docs.cascade.kz/en/faq/otlichie-ot-virtualnyh-nomerov ### How to store the API key safely? Server-side secrets/env only. Do not put it in the frontend, a mobile build, or a public git repo. https://docs.cascade.kz/en/faq/bezopasnost-klyucha ### What if the SMS did not arrive? Check the channel, balance, phone format, and history status; wait and retry; consider WhatsApp/Telegram. https://docs.cascade.kz/en/faq/chto-delat-esli-sms-ne-prishla ### What if the user entered the wrong code? Verify returns an error. Allow a limited number of attempts and offer a resend. https://docs.cascade.kz/en/faq/chto-esli-nevernyy-kod ### What is a Bearer token? The Authorization: Bearer method in the HTTP header for API access. https://docs.cascade.kz/en/faq/chto-takoe-bearer ### What is the channel field? An explicit channel: whatsapp, telegram or sms. If omitted — the company default from the cabinet. https://docs.cascade.kz/en/faq/chto-takoe-channel ### What is cascade delivery? If one delivery method is less cost-effective or less effective, the system uses another. Messages stay cheaper and arrive more often. https://docs.cascade.kz/en/faq/chto-takoe-kaskadnaya-dostavka ### What is the purpose field? A scenario label (default verification). Helps separate registration, login, and payments. https://docs.cascade.kz/en/faq/chto-takoe-purpose ### What is Cascade’s REST API? An HTTPS JSON API with /otp/send, /otp/verify, /links/*, /group/send resources. https://docs.cascade.kz/en/faq/chto-takoe-rest-api ### Is it suitable for fintech? As a code delivery channel — yes, but compliance and antifraud remain on your product’s side. https://docs.cascade.kz/en/faq/dlya-fintech ### Is it suitable for QA? Yes, for checking registration/login flows. Use the team’s test numbers and limits. https://docs.cascade.kz/en/faq/dlya-qa-testirovaniya ### Is it suitable for SaaS? Yes: invite, login, recover access. See /use-cases/saas and blog posts. https://docs.cascade.kz/en/faq/dlya-saas ### Is there an API? Yes. A REST API with Bearer auth: send, verify, short links, group notify. See /api and OpenAPI. https://docs.cascade.kz/en/faq/est-li-api ### Is there a personal cabinet? Yes. In the cabinet — keys, balance/send history, channel settings, and company management. https://docs.cascade.kz/en/faq/est-li-lichnyy-kabinet ### Is there OpenAPI? Yes: https://cascade.kz/openapi.yaml https://docs.cascade.kz/en/faq/est-li-openapi ### Where to view message history? In the personal cabinet. Also see notes on /api/history. https://docs.cascade.kz/en/faq/gde-smotret-istoriyu ### Where are comparisons with alternatives? The /compare section. Unverified competitor figures are marked. https://docs.cascade.kz/en/faq/gde-sravneniya ### Where to check service status? The /status page. During incidents also check the changelog. https://docs.cascade.kz/en/faq/gde-status-servisa ### Which languages is the site in? UI: ru/en/kk. Switch via cookie/hl. SEO content is primarily in Russian for now. https://docs.cascade.kz/en/faq/hreflang-i-yazyki ### Can it be integrated into a mobile app? Yes, but keep the API key on the backend. The app calls your server; your server calls Cascade. https://docs.cascade.kz/en/faq/integraciya-v-mobilnoe ### How fast do messages arrive? Usually seconds, but it depends on the channel and network. Messengers often feel faster to users. https://docs.cascade.kz/en/faq/kak-bystro-prihodyat-soobshcheniya ### How to start in 2–3 minutes? Sign up → key → POST /otp/send → POST /otp/verify. Done. https://docs.cascade.kz/en/faq/kak-nachat-za-2-minuty ### How to choose a delivery channel? Start with a messenger for price and UX; SMS as backup. Or the company default/auto logic. https://docs.cascade.kz/en/faq/kak-otlichit-kanaly ### How to send OTP? Call POST /api/otp/send with the phone field and a Bearer token. The user gets the code on the chosen channel. https://docs.cascade.kz/en/faq/kak-otpravit-otp ### How to get an API key? Open the company cabinet, go to API keys, create a key and copy it. Store it only on the server. https://docs.cascade.kz/en/faq/kak-poluchit-api-klyuch ### How to top up the balance? Via the company cabinet (including payment/Kaspi flows in the product). See /api/top-up and /pricing. https://docs.cascade.kz/en/faq/kak-popolnit-balans ### How to verify OTP? Call POST /api/otp/verify with phone and code. On success the server returns success: true. https://docs.cascade.kz/en/faq/kak-proverit-otp ### How does Cascade OTP work? Cascade accepts an API request, delivers a code to a real phone via the chosen channel, and verifies the user’s input. https://docs.cascade.kz/en/faq/kak-rabotaet-otp-cascade ### How to calculate OTP cost? Count tokens by channel and packages on /pricing. SMS costs more than messengers. https://docs.cascade.kz/en/faq/kak-schitat-stoimost ### How to contact support? See /contacts and the support email from the product configuration. https://docs.cascade.kz/en/faq/kak-soobshchit-ob-oshibke ### How to link OTP to a user session? On the backend, link phone/purpose to the user id before send and after a successful verify. https://docs.cascade.kz/en/faq/kak-svyazat-s-sessiey ### What use cases are there? See /use-cases: SaaS, business, developers, QA, automation, marketing, Telegram, and more. https://docs.cascade.kz/en/faq/kakie-est-use-cases ### Where is the full documentation? /docs, OpenAPI /openapi.yaml, and the /api and /sdk sections. https://docs.cascade.kz/en/faq/kakie-stranitsy-dokumentacii ### What phone number format is required? Digits; + and spaces are allowed. Normalization produces forms like 7700…; length 10–15 digits. https://docs.cascade.kz/en/faq/kakoy-format-telefona ### How do short links work? Pass link in /otp/send or use /links/* — the URL is shortened and can go in the same message. https://docs.cascade.kz/en/faq/korotkie-ssylki ### Can workflows be automated? Yes — via the REST API and server workers. Do not automate code guessing. https://docs.cascade.kz/en/faq/mozhno-li-avtomatizirovat ### Can it be used for arbitration? If you mean delivering OTP to your users — yes. If you mean mass signup on third-party services via virtual numbers — Cascade is not for that. https://docs.cascade.kz/en/faq/mozhno-li-dlya-arbitrazha ### Can it be used for CRM/ERP? Yes, as a confirmation channel inside processes. See /use-cases/business. https://docs.cascade.kz/en/faq/mozhno-li-dlya-crm ### Can there be multiple API keys? Yes, create separate keys for environments/services in the cabinet. https://docs.cascade.kz/en/faq/mozhno-li-neskolko-klyuchey ### Can a code and a link be sent together? Yes, pass link in /otp/send — the short link is added to the same message. https://docs.cascade.kz/en/faq/mozhno-li-otp-i-ssylka-vmeste ### Can the code be resent? Yes, subject to the per-number rate limit. Do not spam the user. https://docs.cascade.kz/en/faq/mozhno-li-povtorno-otpravit ### Can Telegram be used? Yes. Telegram is supported as an OTP delivery channel when the company is configured for it. https://docs.cascade.kz/en/faq/mozhno-li-telegram ### Can only SMS be used? Yes, you can set channel=sms. Note that SMS costs more tokens than messengers. https://docs.cascade.kz/en/faq/mozhno-li-tolko-sms ### Can WhatsApp be used? Yes. WhatsApp is one of Cascade’s main channels for OTP and short links. https://docs.cascade.kz/en/faq/mozhno-li-whatsapp ### Is an official SDK required? You can work over HTTP. /sdk has JS/TS/Python/PHP/Go/Java/C#/Rust examples. https://docs.cascade.kz/en/faq/nuzhen-li-sdk ### Is HTTPS required? Yes. The API is available over HTTPS; call it only from the server. https://docs.cascade.kz/en/faq/nuzhen-li-ssl ### Do you need your own DB for OTP? Cascade stores the code for verify. You need business-scenario statuses, antifraud, and audit. https://docs.cascade.kz/en/faq/nuzhna-li-baz-dlya-otp ### What does error 401 mean? Invalid or missing API token. Check Bearer and that the key is active. https://docs.cascade.kz/en/faq/oshibka-401 ### What does error 422 mean? Validation, balance, channel, or invalid/expired code — read message in the response. https://docs.cascade.kz/en/faq/oshibka-422 ### What does error 429 mean? Too many verify attempts. Slow down retries and respect the limits. https://docs.cascade.kz/en/faq/oshibka-429 ### Why is it so cheap? Cascade delivery prefers more cost-effective channels (messengers), so average cost is lower than classic SMS broadcasts. https://docs.cascade.kz/en/faq/pochemu-tak-deshevo ### Why choose Cascade? Price from 3 ₸, quick start ~3 min, WhatsApp+Telegram+SMS, simple API and cabinet. https://docs.cascade.kz/en/faq/pochemu-vybrat-cascade ### What is group notify? POST /group/send sends text to a WhatsApp group by name or id. https://docs.cascade.kz/en/faq/podderzhivaetsya-li-group-notify ### Can an online store be connected? Yes: codes for registration/login and short links to an order or payment. https://docs.cascade.kz/en/faq/podklyuchit-internet-magazin ### Is the service suitable for a startup? Yes. Quick start, a clear API, and lower average cost thanks to messengers. https://docs.cascade.kz/en/faq/podoydet-li-startapu ### What rate limits exist? There are limits on send frequency (about once a minute per number) and on verify attempts. See /api/rate-limits. https://docs.cascade.kz/en/faq/rate-limits ### How much does a message cost? Marketing orientation — from 3 ₸. Pricing: WhatsApp/Telegram = 3 ₸, SMS = 8 ₸. See current packages on /pricing. https://docs.cascade.kz/en/faq/skolko-stoit-soobshchenie ### How long does setup take? Usually about 3 minutes: registration, key, first send/verify request. https://docs.cascade.kz/en/faq/skolko-zanimaet-podklyuchenie ### SMS verification via Cascade Cascade can deliver OTP by SMS if the channel is enabled in the cabinet; SMS costs more tokens than messengers. https://docs.cascade.kz/en/faq/sms-verifikaciya ### How long does the code live? Usually expires_in is about 300 seconds. After expiry a new send is required. https://docs.cascade.kz/en/faq/ttl-koda ### Are there webhooks? Outbound webhooks are described in the docs. See /api/webhooks and INTEGRATION docs. https://docs.cascade.kz/en/faq/webhooks ## Integration guide (Markdown) # Cascade OTP API — полная инструкция для разработчика и AI-агентов > **Как пользоваться этим файлом** > > 1. Скачай этот `.md` из кабинета Cascade. > 2. Создай API-ключ в кабинете → **API-ключи**. > 3. Положи файл в корень своего проекта (или в `docs/`). > 4. Открой Cursor / Claude Code / Codex и вставь промпт из раздела ниже, подставив свой ключ. > 5. Агент сам добавит клиент, env и вызовы `send` / `verify`. **Сервис:** Cascade (OTP через WhatsApp / Telegram / SMS) **Кабинет:** https://cascade.kz/cabinet **Базовый URL API:** `https://cascade.kz/api` **OpenAPI:** https://cascade.kz/openapi.yaml **HTML-документация:** https://cascade.kz/docs --- ## Промпт для Cursor / Claude Code / Codex Скопируй целиком и замени `PASTE_API_KEY_HERE` на свой ключ: ```text В этом проекте нужно подключить Cascade OTP API по документации из файла cascade-otp-integration.md (или docs/cascade-otp-integration.md). Конфиг: - BASE_URL = https://cascade.kz/api - OTP_API_TOKEN = PASTE_API_KEY_HERE - Ключ храни только в .env / secrets, никогда во фронтенде и публичном репозитории. Сделай: 1. Добавь OTP_API_TOKEN (и при необходимости OTP_API_BASE_URL) в .env.example и .env. 2. Реализуй маленький backend-клиент (на стеке этого проекта) с методами: - sendOtp(phone, purpose?, channel?, link?) - verifyOtp(phone, code, purpose?) 3. Вызывай API ТОЛЬКО с бэкенда (server-side). Не вызывай из браузера. 4. В каждый send/verify добавь заголовок Origin (или X-Cascade-Client-Domain) с доменом, к которому привязан ключ в кабинете. 5. Добавь минимальный flow: форма телефона → send → форма кода → verify → успех. 6. Обрабатывай success=false и HTTP 401/422: показывай message пользователю. 7. Нормализуй телефон к цифрам (KZ: 8XXXXXXXXXX → 7XXXXXXXXXX). 8. По умолчанию НЕ передавай channel — используется канал компании из кабинета. 9. Таймер повторной отправки OTP ≥ 120 секунд (кулдаун на номер). 10. Не логируй API-токен и OTP-коды в открытом виде. 11. После интеграции кратко опиши, какие файлы изменены и как протестировать curl-ом. Следуй спецификации эндпоинтов и примеров из этого же markdown-файла. ``` --- ## Что это за сервис Cascade отправляет одноразовые коды (OTP) на телефон клиента через: | Канал | Значение `channel` | Когда использовать | |-------|--------------------|--------------------| | WhatsApp | `whatsapp` | По умолчанию у большинства компаний | | Telegram | `telegram` | Если включён в кабинете («Откуда отправлять») | | SMS | `sms` | Если включён; обычно дороже (больше токенов) | **Типичный сценарий** 1. Пользователь вводит телефон у вас. 2. Ваш бэкенд: `POST /api/otp/send`. 3. Клиент получает код в мессенджере / SMS. 4. Пользователь вводит код у вас. 5. Ваш бэкенд: `POST /api/otp/verify`. 6. При `success: true` — логин / регистрация / подтверждение операции. Каждая **успешная** доставка списывает токены с баланса компании (WhatsApp/Telegram обычно 1, SMS — по тарифу в кабинете). --- ## Быстрый старт (5 минут) 1. https://cascade.kz/cabinet → **API-ключи** → **Создать** → название сайта + https-ссылка → файл `/.well-known/cascade-otp.txt` → скопировать ключ. 2. Пополнить баланс при необходимости. 3. В кабинете в разделе **Откуда отправлять** выбрать каналы и канал по умолчанию. 4. Проверка: ```bash export OTP_API_TOKEN='ваш_ключ' curl -sS -X POST "https://cascade.kz/api/otp/send" \ -H "Authorization: Bearer $OTP_API_TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -H "Origin: https://ваш-сайт.kz" \ -d '{"phone":"77001234567","purpose":"verification"}' ``` 5. Код придёт на телефон → проверка: ```bash curl -sS -X POST "https://cascade.kz/api/otp/verify" \ -H "Authorization: Bearer $OTP_API_TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -H "Origin: https://ваш-сайт.kz" \ -d '{"phone":"77001234567","code":"123456","purpose":"verification"}' ``` --- ## Авторизация Все эндпоинты ниже требуют: ```http Authorization: Bearer Content-Type: application/json Accept: application/json Origin: https://your-site.kz ``` | HTTP | Значение | |------|----------| | `401` | Нет / неверный токен | | `200` | Успех (`success: true`) | | `422` | Бизнес-ошибка или валидация (`success: false` или `errors`) | Всегда смотри поле `success` в JSON, не только статус. --- ## Формат телефона Поле `phone` — строка. Сервер нормализует (оставляет цифры). | Ввод | Станет | |------|--------| | `+7 700 123 45 67` | `77001234567` | | `87001234567` | `77001234567` | | `77001234567` | `77001234567` | Правила: после нормализации **10–15 цифр**; казахстанский `8…` (11 цифр) → `7…`. На своей стороне можно слать как есть; лучше заранее нормализовать. --- ## POST /api/otp/send Отправить OTP. ### Body | Поле | Тип | Обязательно | Описание | |------|-----|-------------|----------| | `phone` | string | да | Телефон получателя | | `purpose` | string | нет | Сценарий, по умолчанию `verification`. Тот же `purpose` нужен в `verify` | | `channel` | string | нет | `whatsapp` \| `telegram` \| `sms`. Если не указан — канал/авто из настроек компании в кабинете | | `link` | string (URL) | нет | Опциональный http(s) URL: укорачивается и добавляется в то же сообщение, что и код. Успешная отправка = списание токенов как обычно | | `link_expires_in` | int | нет | TTL короткой ссылки, сек (`60`…`2592000`) | ### Пример ```json { "phone": "77001234567", "purpose": "registration" } ``` С явным каналом: ```json { "phone": "77001234567", "purpose": "login", "channel": "whatsapp" } ``` С ссылкой в том же сообщении: ```json { "phone": "77001234567", "purpose": "verification", "link": "https://example.com/confirm/abc", "link_expires_in": 3600 } ``` ### Успех — `200` ```json { "success": true, "message": "OTP отправлен через WhatsApp", "expires_in": 300, "short_url": "https://cascade.kz/s/Ab3xK9" } ``` `short_url` есть только если передан `link`. `expires_in` — жизнь кода в секундах (обычно 300). ### Ошибки — `422` (примеры) ```json { "success": false, "message": "Неверный формат номера телефона" } ``` ```json { "success": false, "message": "Недостаточно токенов рассылки. Пополните баланс." } ``` ```json { "success": false, "message": "Подождите перед повторной отправкой OTP" } ``` ```json { "success": false, "message": "На этот номер уже недавно отправляли сообщение. Подождите 2 мин." } ``` ```json { "success": false, "message": "WhatsApp не подключён. Обратитесь к администратору." } ``` ```json { "success": false, "message": "Закреплённый номер WhatsApp для этого клиента временно недоступен. Попробуйте позже." } ``` Канал, выключенный в кабинете, тоже вернёт `422` с понятным `message`. ### Частые ошибки `otp/send` | `message` | Что значит | Что делать | |-----------|------------|------------| | `Неверный формат номера телефона` | Номер не прошёл нормализацию | Проверьте `phone` (10–15 цифр) | | `Недостаточно токенов рассылки…` | Нет баланса | Пополните в кабинете | | `Подождите перед повторной отправкой OTP` | Rate limit на номер | Подождите ~1–2 мин, покажите таймер | | `На этот номер уже недавно отправляли…` | Кулдаун после успешной доставки (120 сек) | Не спамьте `send`, ждите 2 мин | | `WhatsApp не подключён…` | Нет активной WA-сессии | Обратитесь в поддержку / админку | | `Ошибка WhatsApp-сервиса…` | WA Web не смог доставить (часто «No LID» / нет WhatsApp у номера) | Проверьте, что у получателя есть WhatsApp; повторите позже | | `Invalid API token` / `API token required` | Нет/неверный Bearer | Проверьте ключ из кабинета | | `Аккаунт приостановлен…` | Компания заблокирована | Свяжитесь с поддержкой | > OTP уходит с **любого подключённого и рабочего** WhatsApp/Telegram номера (балансировка нагрузки). Клиенты к конкретным номерам **не закрепляются**. --- ## POST /api/otp/verify Проверить код. ### Body | Поле | Тип | Обязательно | Описание | |------|-----|-------------|----------| | `phone` | string | да | Тот же номер, что в `send` | | `code` | string | да | Код из сообщения | | `purpose` | string | нет | Тот же, что в `send` (по умолчанию `verification`) | ### Пример ```json { "phone": "77001234567", "code": "482910", "purpose": "registration" } ``` ### Успех — `200` ```json { "success": true, "message": "Номер подтверждён" } ``` Код одноразовый. Повторный `verify` того же кода → ошибка. ### Ошибка ```json { "success": false, "message": "Неверный или просроченный код" } ``` Возможен `429`, если слишком много попыток. --- ## Каналы доставки - Если **`channel` не передан** — используется настройка компании: фиксированный канал или `auto` (WhatsApp ↔ Telegram с фолбэком), см. кабинет **Откуда отправлять**. - Если **`channel` передан** — используется он, но только если канал разрешён компании. - Для продакшена чаще всего достаточно **не указывать** `channel` и настроить дефолт в кабинете. Рекомендуемый UX-текст пользователю: «Код придёт в WhatsApp» / «в Telegram» / «по SMS» — в зависимости от вашего дефолта. --- ## POST /api/group/send Уведомление в WhatsApp-группу (не OTP). Авторизация тем же Bearer-токеном. ### Body | Поле | Тип | Обязательно | Описание | |------|-----|-------------|----------| | `group` | string | да | Название группы **или** id (`120363…@g.us` / числовой id) | | `message` | string | да | Текст (до 4096 символов) | ### Примеры ```bash curl -sS -X POST "https://cascade.kz/api/group/send" \ -H "Authorization: Bearer $OTP_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"group":"Бизнес чат","message":"Новая заявка #123 оплачена"}' ``` ```json { "group": "120363411273110879@g.us", "message": "Алерт: баланс ниже порога" } ``` ### Успех — `200` ```json { "success": true, "message": "Сообщение отправлено в группу", "error_code": null, "group_id": "120363411273110879@g.us", "group_name": "Бизнес чат", "message_id": "true_120363…@g.us_XXXXXXXX" } ``` ### Ошибки | HTTP | `error_code` | Когда | |------|--------------|-------| | `401` | — | Нет / неверный токен | | `404` | `group_not_found` | Группа не найдена по названию | | `409` | `group_ambiguous` | Несколько групп с похожим именем — укажите `group_id` | | `422` | `invalid_group` / `send_failed` | Валидация / ошибка отправки | | `503` | `not_connected` | WhatsApp не подключён | **Рекомендация:** один раз отправьте по названию, сохраните `group_id` из ответа и дальше всегда шлите по id. Аккаунт WhatsApp Cascade должен быть участником группы. Таймаут клиента — **60–90 сек**. --- ## Дополнительные API ### POST /api/links/shorten Укоротить URL **без** отправки. Токены **не** списываются. ```json { "url": "https://example.com/very/long", "alias": "promo-may", "expires_in": 86400 } ``` ### POST /api/links/send Укоротить и отправить ссылку на телефон (без генерации OTP). Списывает токены за доставку. ```json { "phone": "77001234567", "url": "https://example.com/promo", "channel": "whatsapp", "text": "Ваша ссылка: :link" } ``` --- ## Ограничения по умолчанию | Параметр | Значение | |----------|----------| | Длина кода | 6 цифр | | TTL кода | 300 сек (5 мин) | | Кулдаун на номер после успешной доставки | **120 сек (2 мин)** | | Повторный `send` (rate limit) | ~60–120 сек | | Лимиты по API-токену / IP | есть (send / verify) | | Выбор номера отправителя | любой подключённый WA/TG (least-loaded) | Шаблон сообщения (примерно): > Ваш код подтверждения: **123456**. Действителен 5 мин. Не сообщайте код никому. --- ## Примеры кода ### Env ```env OTP_API_BASE_URL=https://cascade.kz/api OTP_API_TOKEN=ваш_ключ_из_кабинета ``` ### PHP (Laravel) ```php baseUrl = rtrim($baseUrl ?? (string) config('services.otp.base_url', 'https://cascade.kz/api'), '/'); $this->token = $token ?? (string) config('services.otp.token', ''); } /** @param array{purpose?: string, channel?: string, link?: string, link_expires_in?: int} $options */ public function send(string $phone, array $options = []): array { $payload = array_filter([ 'phone' => $phone, 'purpose' => $options['purpose'] ?? 'verification', 'channel' => $options['channel'] ?? null, 'link' => $options['link'] ?? null, 'link_expires_in' => $options['link_expires_in'] ?? null, ], static fn ($v) => $v !== null && $v !== ''); $response = Http::withToken($this->token) ->acceptJson() ->timeout(30) ->post("{$this->baseUrl}/otp/send", $payload); return $response->json() ?? ['success' => false, 'message' => 'Empty response']; } public function verify(string $phone, string $code, string $purpose = 'verification'): array { $response = Http::withToken($this->token) ->acceptJson() ->timeout(30) ->post("{$this->baseUrl}/otp/verify", [ 'phone' => $phone, 'code' => $code, 'purpose' => $purpose, ]); return $response->json() ?? ['success' => false, 'message' => 'Empty response']; } public function sendOrFail(string $phone, array $options = []): array { $result = $this->send($phone, $options); if (! ($result['success'] ?? false)) { throw new RuntimeException((string) ($result['message'] ?? 'OTP send failed')); } return $result; } } ``` `config/services.php`: ```php 'otp' => [ 'base_url' => env('OTP_API_BASE_URL', 'https://cascade.kz/api'), 'token' => env('OTP_API_TOKEN'), ], ``` ### Node.js / TypeScript ```ts const BASE_URL = process.env.OTP_API_BASE_URL ?? 'https://cascade.kz/api'; const TOKEN = process.env.OTP_API_TOKEN!; type SendOptions = { purpose?: string; channel?: 'whatsapp' | 'telegram' | 'sms'; link?: string; link_expires_in?: number; }; async function sendOtp(phone: string, options: SendOptions = {}) { const res = await fetch(`${BASE_URL}/otp/send`, { method: 'POST', headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify({ phone, purpose: options.purpose ?? 'verification', ...(options.channel ? { channel: options.channel } : {}), ...(options.link ? { link: options.link } : {}), ...(options.link_expires_in ? { link_expires_in: options.link_expires_in } : {}), }), }); return res.json() as Promise<{ success: boolean; message?: string; expires_in?: number; short_url?: string }>; } async function verifyOtp(phone: string, code: string, purpose = 'verification') { const res = await fetch(`${BASE_URL}/otp/verify`, { method: 'POST', headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify({ phone, code, purpose }), }); return res.json() as Promise<{ success: boolean; message?: string }>; } export { sendOtp, verifyOtp }; ``` ### Python ```python import os import requests BASE_URL = os.getenv("OTP_API_BASE_URL", "https://cascade.kz/api").rstrip("/") TOKEN = os.environ["OTP_API_TOKEN"] HEADERS = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", "Accept": "application/json", } def send_otp(phone: str, purpose: str = "verification", channel: str | None = None, link: str | None = None) -> dict: payload = {"phone": phone, "purpose": purpose} if channel: payload["channel"] = channel if link: payload["link"] = link r = requests.post(f"{BASE_URL}/otp/send", json=payload, headers=HEADERS, timeout=30) return r.json() def verify_otp(phone: str, code: str, purpose: str = "verification") -> dict: r = requests.post( f"{BASE_URL}/otp/verify", json={"phone": phone, "code": code, "purpose": purpose}, headers=HEADERS, timeout=30, ) return r.json() ``` --- ## Webhooks (исходящие) В кабинете: **Интеграция → Webhooks**. События: `otp.sent`, `otp.verified`, `otp.failed`. ```http POST <ваш_url> Content-Type: application/json X-Webhook-Event: otp.sent X-Webhook-Signature: sha256= ``` Подпись: HMAC-SHA256 сырого тела с секретом webhook. ```php $expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret); hash_equals($expected, $request->header('X-Webhook-Signature')); ``` --- ## Чеклист для агента после интеграции - [ ] `OTP_API_TOKEN` только в env/secrets - [ ] Вызовы только с сервера - [ ] `send` + `verify` с одинаковым `purpose` - [ ] UI показывает `message` при ошибке - [ ] Таймер повторной отправки ≥ **120 сек** - [ ] Обработаны сообщения про кулдаун и ошибки WhatsApp-сервиса - [ ] Тестовый curl `send`/`verify` на реальный номер прошёл - [ ] В кабинете видна запись в **Отправленные коды** - [ ] (опционально) `group/send` протестирован, сохранён `group_id` --- ## Карта эндпоинтов | Метод | Путь | Назначение | |-------|------|------------| | `POST` | `/api/otp/send` | Отправить OTP | | `POST` | `/api/otp/verify` | Проверить OTP | | `POST` | `/api/group/send` | Текст в WhatsApp-группу | | `POST` | `/api/links/shorten` | Укоротить URL (бесплатно) | | `POST` | `/api/links/send` | Укоротить и отправить ссылку | --- ## Поддержка - Кабинет: https://cascade.kz/cabinet - Docs: https://cascade.kz/docs - Скачать MD: https://cascade.kz/cascade-otp-integration.md - OpenAPI: https://cascade.kz/openapi.yaml - Email: support@cascade.kz Версия документа: **2026-07-29** · API base `https://cascade.kz/api`