Channels

SMS

Send and verify OTP codes via SMS using the SecureOTP API.

SMS

SecureOTP delivers OTP codes over SMS through a global carrier network. This is the simplest channel to set up — no additional configuration is required beyond an active API key and sufficient credits.

Send an OTP

POST /api/v1/otp/sms/send

Sends a 6-character OTP to the specified phone number via SMS.

Request

bash
curl -X POST https://otp.applicanity.com/api/v1/otp/sms/send \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "phone": "+628123456789" }'

Body parameters

| Parameter | Type | Required | Description | | --- | --- | --- | --- | | phone | string | Yes | Recipient phone number in E.164 format (e.g. +628123456789) |

Response

json
{
  "message": "OTP sent successfully",
  "expiresAt": "2026-06-09T10:05:00.000Z"
}

| Field | Type | Description | | --- | --- | --- | | message | string | Confirmation message | | expiresAt | string (ISO 8601) | When the code expires. Use this to drive countdown timers in your UI |

Error responses

| Status | Error | Description | | --- | --- | --- | | 400 | Phone number is required | phone field missing from request body | | 402 | Insufficient balance | Account balance is below the SMS cost (499 credits) | | 500 | Failed to send OTP | Carrier error or internal failure |


Verify an OTP

POST /api/v1/otp/sms/verify

Checks whether a code submitted by the user is valid for the given phone number.

Request

bash
curl -X POST https://otp.applicanity.com/api/v1/otp/sms/verify \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "phone": "+628123456789", "code": "A3K9PZ" }'

Body parameters

| Parameter | Type | Required | Description | | --- | --- | --- | --- | | phone | string | Yes | The phone number that received the OTP | | code | string | Yes | The code entered by the user |

Response — success

json
{
  "success": true,
  "message": "OTP verified successfully",
  "phone": "+628123456789"
}

Response — failure

json
{
  "success": false,
  "message": "Invalid or expired OTP"
}

| Field | Type | Description | | --- | --- | --- | | success | boolean | true if the code matched and was valid | | message | string | Human-readable outcome | | phone | string | Echoed phone number (only on success) |

A failed verification returns HTTP 400. Once a code is verified successfully it is consumed — the same code cannot be verified again.


JavaScript Example

javascript
// 1. Send OTP
const sendRes = await fetch('/api/v1/otp/sms/send', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.SECUREOTP_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ phone: '+628123456789' }),
})
const { expiresAt } = await sendRes.json()

// 2. Later — verify code entered by user
const verifyRes = await fetch('/api/v1/otp/sms/verify', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.SECUREOTP_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ phone: '+628123456789', code: userInput }),
})
const { success } = await verifyRes.json()

if (success) {
  // proceed with authenticated action
}

Notes

  • Phone numbers must include the country code in E.164 format (e.g. +62 for Indonesia, +1 for the US).
  • Sending a new OTP to the same number automatically invalidates any previous unused code for that number.
  • The OTP message includes your account name, the code, and the TTL. See OTP API for message format details.