# Send and check one-time codes (OTP)

> SkedX Flow sends and verifies one-time codes. Turn it on in Settings → Developers → OTP / Verification → Configuration → Enable OTP (Test mode answers with testCode and sends nothing). Then, with an API key allowed to use OTP (otp:send, or full access): POST https://flowserver.skode.ai/api/v1/otp/send/ with {"to": "+<number>" or an email, "channel": "auto" | "whatsapp" | "sms" | "email"} returns {requestId, channelUsed, expiresInSec}; POST /api/v1/otp/verify/ with {"requestId", "code"} returns {verified: true, receiptId, verifiedAt} or {verified: false, reason, attemptsLeft}; GET /api/v1/otp/{requestId}/ returns its status. Defaults: 6-digit codes, 5 minutes, 3 attempts, 45 seconds between sends, 5 an hour per number and 1,000 an hour per workspace; only +91 numbers until you allow more countries. Each send is charged at WhatsApp’s authentication rate and refunded if delivery fails. A WhatsApp code reaches someone who hasn’t written to you in 24 hours only through an approved authentication template (Advanced → WhatsApp AUTH template id); without one, auto moves on to the next channel.

Product: SkedX Flow · Topic: APIs & Developers · Draft — steps not yet re-verified in the live product

Flow can send a one-time code to a customer’s WhatsApp, phone or email, and tell your website whether the code they typed is right. Your site makes two requests — send, then check — and Flow handles the code, the message, expiry and retries. About six minutes to set up.

## Step 1: Turn OTP on

In Flow, open **Settings -> Developers -> OTP / Verification**, go to **Configuration** and switch on **Enable OTP**. While you build, also switch on **Test mode**: every answer then includes the code as `testCode`, and nothing is sent or charged. (Without the Developers tab, OTP / Verification sits under **Settings -> AI & Automation**.)
Open it directly: https://flow.skode.ai/settings/?tab=otp

## Step 2: Choose the rules

On the same screen: **Code length** (4, 6 or 8; 6 recommended — phones auto-fill numeric codes), **Code type**, **Expiry (seconds)** from 60 to 1800 (5 minutes by default), **Max attempts** before the code is blocked (3 by default), **Resend cooldown** and **Max resends / hour (per number)**, the **Channel order** to try, your **Brand name in message**, and **Allowed countries** — only `+91` until you add more, which stops costly foreign sends. For WhatsApp, open **Advanced — WhatsApp template & SMS DLT (India)**: **WhatsApp AUTH template id** holds the id of an approved authentication template on your number. Without one, a WhatsApp code goes as a plain message, which WhatsApp delivers only to people who have written to you in the last 24 hours — everyone else gets the next channel in your order. Message us to set the template up.

## Step 3: Send a code

From your website’s server, send `POST /api/v1/otp/send/` with the customer’s number (with its country code) or email in `to`, and a `channel`: `auto` tries your channel order; `whatsapp`, `sms` or `email` pins one. The key needs **Send and check one-time codes**, or full access. Keep the `requestId` that comes back. In Test mode the answer also carries the code itself as `testCode`, and nothing is sent.

Request:
```bash
curl -s -X POST "https://flowserver.skode.ai/api/v1/otp/send/" \
  -H "Authorization: Bearer $FLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": "+91XXXXXXXXXX", "channel": "auto"}'
```

Answer:
```json
{"requestId": "…", "channelUsed": "whatsapp", "expiresInSec": 300}
```

## Step 4: If OTP isn’t on yet

Until you switch it on, sending answers `403` with `"error": "otp_disabled"` and a message naming the switch: **Settings -> Developers -> OTP / Verification -> Configuration**.

## Step 5: Check the code the customer typed

Send `POST /api/v1/otp/verify/` with the `requestId` and the `code` (letters are not case-sensitive). A code that doesn’t pass answers `"verified": false` with a `reason` — `wrong_code`, `expired`, `too_many_attempts`, `already_used` or `delivery_failed` — and `attemptsLeft`. `"verified": true` means let them in — keep the `receiptId` as proof.

Request:
```bash
curl -s -X POST "https://flowserver.skode.ai/api/v1/otp/verify/" \
  -H "Authorization: Bearer $FLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"requestId": "<from the send>", "code": "482913"}'
```

Answer when the code is wrong:
```json
{"verified": false, "reason": "wrong_code", "attemptsLeft": 2}
```

## Step 6: Follow up on a code

`GET /api/v1/otp/<requestId>/` returns where a code stands: the number, masked; its `status` — `pending`, `verified`, `expired`, `blocked` after too many wrong tries, or `failed`; the channel used and whether it was delivered (`deliveryStatus` reads `test` in Test mode); how many wrong codes were tried; and when it was sent, expires or was verified.

## Step 7: Limits and cost

By default one number can get a new code every 45 seconds and at most 5 an hour, and your workspace 1,000 an hour. Past a limit, sending answers `429` `"rate_limited"`. Each code sent is charged at WhatsApp’s authentication rate for the customer’s country (or your agreed flat price) and refunded if it can’t be delivered; a low wallet answers `402`.

## Common questions

### Can I test without sending real messages?

Yes — switch on **Test mode** (step 1). Answers include `testCode`, nothing is delivered and nothing is charged. Switch it off before going live.

### Why is a foreign number refused?

Only the countries in **Allowed countries** can get codes — just `+91` at first. Add the calling codes you need, comma-separated.

### Which channel does “auto” use?

The first in your **Channel order** that delivers. The answer’s `channelUsed` says which.

### Can I change the message text?

Yes — **Custom message**, which must include `{code}` and can use `{minutes}` and `{brand}`. It replaces Flow’s own wording: “Your brand: 482913 is your verification code. Valid for 5 minutes. For your security, do not share this code.” A code sent through a WhatsApp authentication template always uses that template’s approved words. In India, SMS wording must match a template registered with the operators (DLT), so message us before changing it for Indian numbers.

## Useful links
- OTP / Verification in Flow — turn it on, set the rules, see the logs: https://flow.skode.ai/settings/?tab=otp
- Flow API reference — the three OTP requests: https://flow.skode.ai/docs/

Videos and screenshots © 2026 SkedX, with sample data only. Share and link to them freely; copying the SkedX product or its design is not allowed. Terms: https://skode.ai/terms/

## Related guides
- Create an API key: https://skode.ai/help/flow/developers/create-an-api-key/
- Flow API errors, and how to fix each one: https://skode.ai/help/flow/developers/flow-api-errors/
- Build your Flow integration with an AI assistant: https://skode.ai/help/flow/developers/build-your-flow-integration-with-ai/

Source: https://skode.ai/help/flow/developers/send-and-check-one-time-codes/