REST API v1

Build with Narvark.

A clean, RESTful API for sending and verifying OTPs across WhatsApp, SMS, email, and voice — with SDKs for Node.js, Python, PHP, and Go.

https://api.narvark.com/v1
Quickstart

Up and running in 5 minutes.

No carrier agreements, no SMPP configuration, no WhatsApp Business setup. Just grab an API key and go.

// step 01
Get your API key

Request access through the Narvark demo form and our team will provide the appropriate onboarding path and API access details.

// step 02
Send your first OTP

POST to /v1/otp/send with a phone number and channel. OTP is dispatched in under 200ms.

// step 03
Verify the code

When the user submits their code, POST to /v1/otp/verify. Get back a boolean valid in milliseconds.

// authentication

API Authentication

All API requests must include your API key in the Authorization header as a Bearer token. API keys are scoped to environments (test / live).

HTTP Header
Authorization: Bearer nvk_live_sk_a1b2c3d4e5f6g7h8i9j0
cURL Example
curl https://api.narvark.com/v1/otp/send \ -H "Authorization: Bearer nvk_live_sk_your_key" \ -H "Content-Type: application/json" \ -d '{"to": "+447911123456", "channel": "sms"}'

Use nvk_test_sk_ keys for development — no OTPs are dispatched and no charges apply. Switch to nvk_live_sk_ for production.

// otp endpoints

Send OTP

Dispatch a one-time password to a phone number or email address via the specified channel. Returns an OTP ID for status tracking and verification.

POST /v1/otp/send

Request Parameters

ParameterTypeRequiredDescription
tostringrequiredRecipient phone number in E.164 format (e.g. +447911123456) or email address.
channelstringrequiredDelivery channel. One of: whatsapp, sms, email, voice.
ttlintegeroptionalCode expiry in seconds. Default: 300. Min: 60. Max: 86400.
fallbackstringoptionalFallback channel if primary fails. E.g. "sms" when primary is "whatsapp".
code_lengthintegeroptionalOTP code length. Default: 6. Options: 4, 6, 8.
templatestringoptionalWhatsApp-only. Pre-approved message template name. Default: "otp_verification".
metadataobjectoptionalArbitrary key-value pairs attached to the OTP. Returned in webhooks and status responses. Max 10 keys.
cURLCopy
curl -X POST https://api.narvark.com/v1/otp/send \ -H "Authorization: Bearer nvk_live_sk_your_key" \ -H "Content-Type: application/json" \ -d '{ "to": "+447911123456", "channel": "whatsapp", "fallback": "sms", "ttl": 300, "metadata": { "user_id": "usr_abc123", "action": "login" } }'
Node.jsCopy
import Narvark from '@narvark/node'; const client = new Narvark('nvk_live_sk_your_key'); const otp = await client.otp.send({ to: '+447911123456', channel: 'whatsapp', fallback: 'sms', ttl: 300, }); console.log(otp.id); // otp_wa_k9x2m
PythonCopy
import narvark client = narvark.Client("nvk_live_sk_your_key") otp = client.otp.send( to="+447911123456", channel="whatsapp", fallback="sms", ttl=300, ) print(otp.id) # otp_wa_k9x2m

Response

200 OK

{
  "id": "otp_wa_k9x2m",
  "status": "sent",
  "channel": "whatsapp",
  "to": "+447911123456",
  "expires_at": "2026-03-27T16:28:00Z",
  "latency_ms": 187,
  "created_at": "2026-03-27T16:23:00Z"
}

Verify OTP

Verify a code submitted by the user against the OTP identified by its ID. Returns whether the code is valid and whether it has been consumed.

POST /v1/otp/verify
ParameterTypeRequiredDescription
idstringrequiredThe OTP ID returned from the send endpoint.
codestringrequiredThe code submitted by the user. Accepts formatted (e.g. "492 817") or unformatted ("492817").
cURL
curl -X POST https://api.narvark.com/v1/otp/verify \ -H "Authorization: Bearer nvk_live_sk_your_key" \ -H "Content-Type: application/json" \ -d '{"id": "otp_wa_k9x2m", "code": "492817"}'
200 OK

{
  "id": "otp_wa_k9x2m",
  "valid": true,
  "consumed": true,
  "verified_at": "2026-03-27T16:24:12Z"
}
400 Invalid Code

{
  "valid": false,
  "error": "code_invalid",
  "attempts_remaining": 2
}

Errors & Rate Limits

Narvark uses standard HTTP status codes. All error responses include a machine-readable error code and human-readable message.

CodeErrorDescription
400invalid_requestMissing or malformed request parameters.
401unauthorizedInvalid or missing API key.
429rate_limitedToo many requests. Default: 1,000 req/min per key. Enterprise: unlimited.
500internal_errorNarvark server error. Automatically retried internally — rare.

Webhooks

Narvark sends real-time POST webhooks to your endpoint for OTP lifecycle events — dispatched, delivered, read, verified, expired, and failed.

Webhook Payload
{
  "event": "otp.delivered",
  "otp_id": "otp_wa_k9x2m",
  "channel": "whatsapp",
  "to": "+447911123456",
  "timestamp": "2026-03-27T16:23:01Z",
  "latency_ms": 187,
  "metadata": { "user_id": "usr_abc123" }
}

Verify webhook authenticity using the X-Narvark-Signature header — an HMAC-SHA256 signature of the raw request body using your webhook secret.