API Documentation

OTP Space takes just two API calls: send an OTP to your user's WhatsApp number, then verify the code they enter. That's it.

Want to try it directly in your browser? Open the interactive API Reference (Swagger UI), paste your sk_live_* key, and fire real requests without writing any code. The 10 free OTPs on every new account are plenty for a smoke test.

Quickstart

Register an account, grab your CLIENT_ID and CLIENT_SECRET from the API Keys page, then start sending:

# 1) Send OTP
curl -X POST https://api.otpspace.com/v1/otp/send \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"phone":"6281234567890"}'

# 2) Verify code
curl -X POST https://api.otpspace.com/v1/otp/verify \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"phone":"6281234567890","code":"123456"}'

Authentication

Every request must include the header Authorization: Bearer sk_live_xxx with your client secret.

Authorization: Bearer sk_live_xxxxxxxxxxxx

Endpoints

POST /v1/otp/send

Send an OTP over WhatsApp (default) or email. Set channel to "email" and pass an email destination, or omit channel and it is inferred from the destination. The template_id, otp_length, expiry_seconds, and metadata fields are optional.

// Request
{
  "phone": "6281234567890",
  "template_id": "default",
  "otp_length": 6,
  "expiry_seconds": 300
}

// Response 202
{
  "success": true,
  "data": {
    "otp_id": "otp_abc123def456",
    "phone": "6281234***90",
    "status": "queued",
    "expires_at": "2026-05-15T14:35:00Z"
  },
  "credits_remaining": 994
}

POST /v1/otp/verify

Verify the OTP code your user entered (WhatsApp or email).

// Request
{
  "phone": "6281234567890",
  "code": "482916"
}

// Response 200
{
  "success": true,
  "data": {
    "otp_id": "otp_abc123def456",
    "phone": "6281234***90",
    "channel": "whatsapp",
    "status": "verified",
    "verified_at": "2026-05-15T14:33:42Z"
  }
}

Email channel

OTP Space can also deliver OTPs by email at 0.2 credit per send (WhatsApp is 1 credit). Use the same /v1/otp/send and /v1/otp/verify endpoints — set channel to "email" and pass an email destination. Everything else (rate limits, expiry, verification) behaves exactly like WhatsApp.

# Send an email OTP (0.2 credit)
curl -X POST https://api.otpspace.com/v1/otp/send \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"channel":"email","email":"[email protected]"}'

// Response 202
{
  "success": true,
  "data": {
    "otp_id": "otp_9f2c1a8b7d6e",
    "destination": "u***@acme.com",
    "channel": "email",
    "status": "delivered",
    "expires_at": "2026-05-15T14:40:00Z"
  },
  "credits_remaining": 993.8
}

# Verify uses the same endpoint; pass the email as the destination
curl -X POST https://api.otpspace.com/v1/otp/verify \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","code":"482916"}'

GET /v1/otp/:otp_id

Check the status of a specific OTP.

// Response 200
{
  "success": true,
  "data": {
    "otp_id": "otp_abc123def456",
    "phone": "6281234***90",
    "status": "delivered",
    "created_at": "2026-05-15T14:30:00Z",
    "expires_at": "2026-05-15T14:35:00Z",
    "delivered_at": "2026-05-15T14:30:08Z",
    "verified_at": null
  }
}

GET /v1/otp/logs

OTP delivery history. Supports status, channel, phone, from, and to filters, plus page and per_page for pagination.

GET /v1/account/balance

Check your account's credit balance.

// Response 200
{
  "success": true,
  "data": {
    "credits_remaining": 8420,
    "credits_used": 1580,
    "tier": "growth"
  }
}

Error codes

Code Meaning How to handle
400 Bad Request Check the request payload format.
401 Unauthorized Client secret is invalid.
402 Payment Required Out of credits. Top up via the dashboard.
404 Not Found OTP ID not found.
410 Gone OTP has expired.
422 Unprocessable Phone number is invalid or not on WhatsApp.
429 Too Many Requests Rate limit reached. Retry after a few seconds.
500 Server Error Retry with backoff. Contact support if persistent.

Webhook

Coming in Phase 2. You'll be able to register a URL to receive real-time event notifications (delivered, verified, expired, failed).