Cascade Cascade

API

API құжаттамасы

WhatsApp арқылы OTP интеграциясы

Қосымшаңызды Cascade сервисіне қосуға арналған құжаттама.

Базалық URL: https://otp.kztusdt.kz/api


Мазмұны

  1. Жалпы схема
  2. API-токенді алу
  3. Авторизация
  4. Телефон нөмірінің пішімі
  5. OTP жіберу
  6. Қысқа сілтемелер
  7. OTP тексеру
  8. Жауап кодтары мен қателер
  9. Шектеулер
  10. Интеграция мысалдары
  11. Ұсыныстар
  12. Шығыс webhooks

Жалпы схема

┌─────────────────┐     POST /otp/send      ┌──────────────────┐
│  Сіздің қосымша  │ ──────────────────────► │  otp.kztusdt.kz  │
│  (сайт, API)     │                         │  Laravel API     │
└────────┬────────┘                         └────────┬─────────┘
         │                                           │
         │  Пайдаланушы кодты енгізеді               │ WhatsApp
         │                                           ▼
         │                                 ┌──────────────────┐
         │     POST /otp/verify            │  Клиент нөмірі   │
         └───────────────────────────────► └──────────────────┘

Типтік сценарий:

  1. Пайдаланушы қосымшаңызда телефон нөмірін енгізеді.
  2. Сіздің бэкенд POST /api/otp/send шақырады.
  3. Клиент көрсетілген нөмірге WhatsApp арқылы код алады.
  4. Пайдаланушы кодты сіздің формаңызда енгізеді.
  5. Сіздің бэкенд POST /api/otp/verify шақырады.
  6. Сәтті болғанда — аккаунтты / кіруді / операцияны растайсыз.

API-токенді алу

  1. Компания кабинетіне кіріңіз: https://otp.kztusdt.kz/cabinet
  2. API-кілттер бөлімін ашыңыз
  3. Жасау батырмасын басыңыз
  4. Атауын көрсетіңіз (мысалы, Менің сайтым)
  5. Кілтті көшіріңіз — оны тізімнен қайта көруге болады («Көрсету» батырмасы)

Токенді тек серверде сақтаңыз (орта айнымалылары, secrets). Оны фронтендке, мобильді қосымшаға немесе ашық репозиторийге салмаңыз.


Авторизация

OTP API-ға барлық сұрауларда мына тақырып қажет:

Authorization: Bearer <СІЗДІҢ_API_ТОКЕНІҢІЗ>
Content-Type: application/json
Accept: application/json

Токен дұрыс емес немесе жоқ болса, сервер 401 Unauthorized қайтарады:

{
  "success": false,
  "message": "Invalid API token"
}

Телефон нөмірінің пішімі

phone өрісі — жол, тек цифрлар немесе пішімдеу таңбаларымен (олар жойылады).

Енгізу Нормаланған түрі
+7 700 123 45 67 77001234567
87001234567 77001234567
77001234567 77001234567

Ережелер:

  • Нормалаудан кейінгі ұзындығы: 10–15 цифр
  • Басында 8 бар нөмір (11 цифр, Қазақстан) автоматты түрде 7… болып ауыстырылады

OTP жіберу

Сұрау

POST /api/otp/send

Дене (JSON):

Өріс Түрі Міндетті Сипаттама
phone string иә Алушының телефон нөмірі
purpose string жоқ Кодтың мақсаты (әдепкі verification)
channel string жоқ whatsapp, telegram, sms немесе auto. Берілмесе — кабинеттегі әдепкі канал (Откуда отправлять). auto WhatsApp пен Telegram нөмірлері арасында жүктемені тең бөледі; Telegram жібермесе — WhatsApp арқылы қайталайды. Өшірілген канал қате қайтарады.
link string жоқ Толық http/https URL — қысқартылып, сол хабарламаға қосылады
link_expires_in integer жоқ Қысқа сілтеменің мерзімі секундпен (60–2592000)

Мысал:

{
  "phone": "77001234567",
  "purpose": "registration",
  "link": "https://example.com/confirm/abc"
}

purpose өрісі әртүрлі сценарийлер үшін кодтарды бөлуге мүмкіндік береді (тіркелу, кіру, құпия сөзді қалпына келтіру). Тексеру кезінде сол purpose берілуі керек.

link берілсе, сервис https://otp.kztusdt.kz/s/Ab3xK9 сияқты қысқа сілтеме жасап, оны кодпен бір хабарламаға қосады. Жеткізу құны: WhatsApp/Telegram = 1 токен, SMS = 16 токен (код+сілтеме бірге құнын екі еселемейді).

Сәтті жауап — 200 OK

{
  "success": true,
  "message": "OTP отправлен через WhatsApp",
  "expires_in": 300,
  "short_url": "https://otp.kztusdt.kz/s/Ab3xK9"
}
Өріс Сипаттама
expires_in Кодтың өмір сүру уақыты секундпен (әдепкі 300 = 5 минут)
short_url Қысқа сілтеме (тек link берілгенде)

Қателер — 422 Unprocessable Entity

{
  "success": false,
  "message": "Неверный формат номера телефона"
}
{
  "success": false,
  "message": "WhatsApp не подключён. Обратитесь к администратору."
}
{
  "success": false,
  "message": "Подождите перед повторной отправкой OTP"
}
{
  "success": false,
  "message": "Не удалось отправить OTP через WhatsApp"
}

Қысқа сілтемелер

Қысқа сілтемелер сол доменде жұмыс істейді: https://otp.kztusdt.kz/s/{slug} → мақсатты URL-ге 302. Кликтар есептеледі. Белсенді емес немесе мерзімі өткен сілтемелер 404 қайтарады.

Басқару — компания кабинетінде (Қысқа сілтемелер): жасау, көшіру, кликтар, мерзім, қосу/өшіру.

Жібермей қысқарту — тегін

POST /api/links/shorten
Өріс Түрі Міндетті Сипаттама
url string иә Мақсатты http/https URL
alias string жоқ Өз slug (3–32: әріптер, цифрлар, -, _)
title string жоқ Кабинетке арналған атау
expires_in integer жоқ Мерзім секундпен
{
  "url": "https://example.com/very/long/path",
  "alias": "promo-may"
}
{
  "success": true,
  "short_url": "https://otp.kztusdt.kz/s/promo-may",
  "slug": "promo-may",
  "expires_at": null
}

Кодсыз сілтеме жіберу — 1 токен

POST /api/links/send
Өріс Түрі Міндетті Сипаттама
phone string иә Алушының нөмірі
url string иә Мақсатты http/https URL
channel string жоқ whatsapp, telegram, sms немесе auto (компания баптауларында рұқсат / жарамды болуы керек)
text string жоқ :link плейсхолдері бар мәтін (әйтпесе әдепкі шаблон)
expires_in integer жоқ Қысқа сілтеменің мерзімі
{
  "phone": "77001234567",
  "url": "https://example.com/promo",
  "text": "Жеңілдік: :link"
}
{
  "success": true,
  "message": "Ссылка отправлена через WhatsApp",
  "short_url": "https://otp.kztusdt.kz/s/Ab3xK9",
  "slug": "Ab3xK9"
}

Биллинг: WhatsApp пен Telegram жеткізуі 1 токен, SMS — 16 токен. auto режимінде алдымен ең аз жүктелген WhatsApp/Telegram нөмірі таңдалады; SMS тек мессенджерлер қолжетімсіз болғанда қолданылады (SMS қосулы, баланс ≥ 16). Жібермей қысқарту тегін.


OTP тексеру

Сұрау

POST /api/otp/verify

Дене (JSON):

Өріс Түрі Міндетті Сипаттама
phone string иә Жіберу кезіндегі сол нөмір
code string иә WhatsApp-тан келген код
purpose string жоқ send кезіндегі сол мән (әдепкі verification)

Мысал:

{
  "phone": "77001234567",
  "code": "482910",
  "purpose": "registration"
}

Сәтті жауап — 200 OK

{
  "success": true,
  "message": "Номер подтверждён"
}

Сәтті тексеруден кейін код бір реттік — сол кодты қайта пайдалану қате қайтарады.

Қате — 422 Unprocessable Entity

{
  "success": false,
  "message": "Неверный или просроченный код"
}

Жауап кодтары мен қателер

HTTP Мағынасы
200 Сәтті (success: true)
401 API-токен жоқ немесе дұрыс емес
422 Бизнес-логика қатесі (success: false)
422 Өрістерді валидациялау қатесі (Laravel validation)

Валидация (мысал):

{
  "message": "The phone field is required.",
  "errors": {
    "phone": ["The phone field is required."]
  }
}

Жауап денесіндегі success өрісін әрдайым тексеріңіз, тек HTTP-статусқа ғана қарамаңыз.


Шектеулер

Параметр Әдепкі мән
Код ұзындығы 6 цифр
Жарамдылық мерзімі 300 сек (5 мин)
Сол нөмірге қайта жіберу 60 сек ішінде 1 реттен жиі емес

WhatsApp хабарламасы (үлгі):

Ваш код подтверждения: 123456. Действителен 5 мин. Не сообщайте код никому.


Интеграция мысалдары

cURL

# OTP жіберу
curl -X POST "https://otp.kztusdt.kz/api/otp/send" \
  -H "Authorization: Bearer СІЗДІҢ_API_ТОКЕНІҢІЗ" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"phone":"77001234567","purpose":"registration"}'

# Кодты тексеру
curl -X POST "https://otp.kztusdt.kz/api/otp/verify" \
  -H "Authorization: Bearer СІЗДІҢ_API_ТОКЕНІҢІЗ" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"phone":"77001234567","code":"482910","purpose":"registration"}'

PHP (Laravel / Guzzle)

<?php

declare(strict_types=1);

use Illuminate\Support\Facades\Http;

final class OtpClient
{
    public function __construct(
        private readonly string $baseUrl = 'https://otp.kztusdt.kz/api',
        private readonly string $token = '', // env('OTP_API_TOKEN')-ден
    ) {}

    public function send(string $phone, string $purpose = 'verification'): array
    {
        $response = Http::withToken($this->token)
            ->acceptJson()
            ->post("{$this->baseUrl}/otp/send", [
                'phone' => $phone,
                'purpose' => $purpose,
            ]);

        return $response->json();
    }

    public function verify(string $phone, string $code, string $purpose = 'verification'): array
    {
        $response = Http::withToken($this->token)
            ->acceptJson()
            ->post("{$this->baseUrl}/otp/verify", [
                'phone' => $phone,
                'code' => $code,
                'purpose' => $purpose,
            ]);

        return $response->json();
    }
}

// Пайдалану
$otp = new OtpClient(token: config('services.otp.token'));

$result = $otp->send('77001234567', 'registration');
if (! ($result['success'] ?? false)) {
    throw new RuntimeException($result['message'] ?? 'OTP send failed');
}

$check = $otp->verify('77001234567', '482910', 'registration');
if ($check['success'] ?? false) {
    // нөмір расталды — сессия жасаңыз / пайдаланушыны белсендіріңіз
}

JavaScript (Node.js / fetch)

const BASE_URL = 'https://otp.kztusdt.kz/api';
const API_TOKEN = process.env.OTP_API_TOKEN;

async function sendOtp(phone, purpose = 'verification') {
  const res = await fetch(`${BASE_URL}/otp/send`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${API_TOKEN}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    body: JSON.stringify({ phone, purpose }),
  });

  return res.json();
}

async function verifyOtp(phone, code, purpose = 'verification') {
  const res = await fetch(`${BASE_URL}/otp/verify`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${API_TOKEN}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    body: JSON.stringify({ phone, code, purpose }),
  });

  return res.json();
}

// Мысал
const sent = await sendOtp('77001234567', 'login');
if (!sent.success) {
  console.error(sent.message);
}

const verified = await verifyOtp('77001234567', '123456', 'login');
if (verified.success) {
  console.log('OK');
}

Python

import os
import requests

BASE_URL = "https://otp.kztusdt.kz/api"
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") -> dict:
    r = requests.post(
        f"{BASE_URL}/otp/send",
        json={"phone": phone, "purpose": purpose},
        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()

Ұсыныстар

Қауіпсіздік

  • API-ды тек бэкендтен шақырыңыз, браузерден тікелей емес.
  • API-токен мен OTP-кодтарды ашық түрде логқа жазбаңыз.
  • Өз жағыңызда код енгізу әрекеттерін шектеңіз (мысалы, 5 әрекет → 15 минутқа бұғаттау).

UX

  • Қайта жіберуге дейін таймер көрсетіңіз (кемінде 60 сек).
  • Пайдаланушыға код WhatsApp-қа келетінін, SMS емес екенін айтыңыз.
  • Нөмірде WhatsApp орнатылған болуы керек.

Әртүрлі сценарийлер (purpose)

purpose Қашан қолдану
registration Жаңа пайдаланушыны тіркеу
login Нөмір бойынша кіру
password_reset Құпия сөзді қалпына келтіру
verification Жалпы верификация (әдепкі)

Бір нөмір үшін бір уақытта әртүрлі purpose бар бірнеше белсенді код болуы мүмкін.

Өз жағыңызда қателерді өңдеу

API хабарламасы Қосымшадағы әрекет
WhatsApp не подключён «Сервис уақытша қолжетімсіз» көрсету, әкімшіге хабарлау
Подождите перед повторной отправкой Таймері бар «Қайта жіберу» батырмасын көрсету
Неверный или просроченный код Кодты қайта енгізуді немесе жаңасын сұрауды ұсыну
Неверный формат номера Телефон өрісін бөлектеу

Продакшенге дейінгі тексеру

  1. Админкада WhatsApp қосылған (WhatsApp → Қосу).
  2. API-токен жасалған және белсенді.
  3. Нақты WhatsApp нөміріне тесттік send + verify.
  4. OTP тарихында жіберу туралы жазба көрінеді.

Шығыс webhooks

Кабинетте (Интеграция → Webhooks) сервис оқиғалар жіберетін URL көрсетуге болады:

Оқиға Қашан
otp.sent Код сәтті жіберілді
otp.verified Код расталды
otp.failed Жіберу / есептен шығару қатесі

Сұрау: JSON-денені POST. Тақырыптар:

Content-Type: application/json
X-Webhook-Event: otp.sent
X-Webhook-Signature: sha256=<hmac_sha256_hex_of_raw_body>

Қолтаңба: webhook құпиясымен сұраудың шикі денесінен HMAC-SHA256 (жасау / ротация кезінде бір рет көрсетіледі).

Тексеру мысалы (PHP):

$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
hash_equals($expected, $request->header('X-Webhook-Signature'));

Payload мысалы:

{
  "id": "evt_01h…",
  "event": "otp.sent",
  "created_at": "2026-07-21T10:00:00+00:00",
  "company_id": 1,
  "data": {
    "otp_log_id": 42,
    "phone": "77001234567",
    "purpose": "verification",
    "status": "sent",
    "api_token_id": 3,
    "session_name": "wa-1",
    "expires_at": "2026-07-21T10:05:00+00:00",
    "verified_at": null,
    "error_message": null
  }
}

Жеткізу асинхронды (кезек). php artisan queue:work қажет. 3 әрекетке дейін қайталау.


Қолдау

Қосу, төлем және сервистің жұмысы бойынша сұрақтар үшін: