Skip to content

Practical integration

How to integrate the OTP API

A basic verification flow needs two server-side calls: send a code and verify the value entered by the user.

Quick Answer

Integrate Cascade on your backend: obtain a Bearer token, send the user's phone to POST /api/otp/send, then submit the entered code with the same phone and purpose to POST /api/otp/verify.

Summary

Create an API key in the dashboard, keep it on the server, call /api/otp/send, and verify the code through /api/otp/verify.

Key Takeaways

  • Never embed the Bearer token in frontend or mobile code.
  • Send phone numbers in international form, for example 77001234567.
  • Use the same purpose for send and verify.
  • Handle HTTP 401, 422, and 429 separately.
  • Public SMS is not live; test with WhatsApp or Telegram.

Before you start

Prepare a backend service, a test phone, and a Cascade account. New accounts receive 1000 starting credits. Create an API key in the dashboard and store it in your backend secrets.

The API base URL is https://cascade.kz/api. Protected requests use:

Authorization: Bearer <token>
Accept: application/json
Content-Type: application/json

Do not place the token in browser JavaScript, a public repository, a mobile bundle, or screenshots. Revoke and replace a key immediately if it is exposed.

Step 1. Send a code

curl -X POST "https://cascade.kz/api/otp/send" \
  -H "Authorization: Bearer $CASCADE_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"phone":"77001234567","purpose":"login","channel":"whatsapp"}'

purpose binds a code to an action such as login, signup, or payment. Keep it short and predictable, and do not include personal data.

The channel field is optional; without it, the company setting is used. WhatsApp and Telegram are publicly available. SMS is represented in the API, but the public SMS provider is not live yet.

A successful response includes success, a message, and expires_in. The standard expiration is 300 seconds.

Step 2. Display the code form

After send succeeds, show a six-digit input, a countdown, and a clear resend action. Do not resend automatically: multiple messages make it unclear which code is current.

The frontend sends the entered code to your backend. It must not call Cascade directly.

Step 3. Verify the code

Submit the same phone and purpose used during send:

curl -X POST "https://cascade.kz/api/otp/verify" \
  -H "Authorization: Bearer $CASCADE_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"phone":"77001234567","code":"482910","purpose":"login"}'

Complete login or the protected action only after success: true. Message delivery and code verification are separate events.

Step 4. Handle failures

HTTP Meaning Recommended action
401 Invalid or revoked API key Check the server secret; do not ask the user to retry the code
422 Invalid data, channel, balance, or code Show a safe message and correct the request
429 Rate limit exceeded Stop immediate retries and apply a delay
5xx Temporary server failure Record the request ID and retry with bounded backoff

Do not expose provider internals to users or log OTP values and Bearer tokens.

Production checklist

  • Cascade calls originate from the backend only.
  • Phone numbers are normalized to international format.
  • purpose matches across send and verify.
  • Send and verification attempts are limited.
  • Resend has a cooldown.
  • The UI handles the five-minute expiration.
  • Responses do not disclose whether an account exists.
  • Balance and delivery status are monitored.
  • The API key can be rotated without rebuilding the client.

See the send, verify, errors, and OpenAPI references for complete request fields.

FAQ

Where should I store the Cascade API key?
On your server only, in a secret manager or environment variable.
Which calls are required for OTP?
POST /api/otp/send sends a code and POST /api/otp/verify verifies it.
Can a browser call Cascade directly?
No. A direct browser call would expose the Bearer token; route it through your backend.