Sending an OTP
4.1 Failover flow – POST /otp/send-failover
Send an OTP with a flow of steps (e.g. Viber then SMS). Each step carries its own content. Optional callback for webhooks.
Request
POST https://connect.routee.net/failover-otp/otp/send-failover
Authorization: Bearer <your_access_token>
Content-Type: application/json
Body (JSON)
| Top-level field | Type | Required | Description |
|---|---|---|---|
| flow | array | Yes | Ordered steps (ViberOtp and/or Sms). Each step has type, to, order, and channel-specific fields. |
| callback | object | No | { "url": "<webhook_url>" }. When provided, url is required. The service POSTs to this URL on status changes and when failover is sent. |
Common step fields (all steps)
| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | "ViberOtp" or "Sms". |
| to | string or array | Yes | Recipient(s) in E.164 format (e.g. "306912345671" or ["+306912345671"] for ViberOtp). |
| order | integer | Yes | Step order in the flow (1, 2, …). Must be unique. |
| ttl | integer | Yes | Time to live in seconds (required per channel; used for message validity and failover timing). |
| label | string | No | Campaign or tracking label. |
Flow order – The channel order is controlled by the order field in each step. You can send SMS first (e.g. order 1) and Viber as failover (order 2), or the reverse; the service follows the configured order.
ViberOtp step – additional fields
| Field | Required | Type | Description |
|---|---|---|---|
| senderInfoTrackingId | Yes | string | Routee Viber OTP sender identifier (from your sender registration). |
| templateId | Yes | string | Routee Viber OTP template UUID. |
| pin | Yes | string | OTP code (4–10 characters). |
| templateType | Required for non-basic templates | string | Template type (e.g. "with_business_name", "with_validity", "with_type", "with_action", "with_reason", "with_type_and_validity", "with_business_and_validity_hours"). When set, the corresponding params below are mandatory. Omit or use "basic" / "basic_5min" for basic templates. |
| businessName | Required if templateType is with_business_name, with_business_and_validity_hours, or with_reason | string | Business/platform name. |
| validityTime | Required if templateType is with_validity, with_type_and_validity, or with_business_and_validity_hours | string | Validity time (e.g. minutes or hours as per template). |
| pinType | Required if templateType is with_type or with_type_and_validity | string | Pin type (e.g. "verification", "login"). |
| actionName | Required if templateType is with_action | string | Action/platform description (e.g. "account verification"). |
| codeReason | Required if templateType is with_reason | string | Reason for the code (e.g. "you requested a password reset"). |
| failoverOnDelivered | No | boolean | When true, SMS failover is also triggered when Viber status is Delivered (after ttl seconds). Default false = failover only on Expired, Failed, Undelivered, Unsent. See §4.2. |
| templateLang | No | string | Language code (e.g. "en"). Default: "en". |
| otpType | No | string | e.g. "PRIMARY_ONLY". |
| seq | No | string | Unique sequence number for the request. |
Sms step – additional fields
| Field | Type | Required | Description |
|---|---|---|---|
| from | string | No | Routee SMS sender ID (alphanumeric or numeric). If omitted, the service default is used. |
| message | object | Yes | Must contain at least body. |
| message.body | string | Yes | SMS text. |
| message.flash | boolean | No | When true, send as flash SMS (display only). |
| message.transcode | boolean | No | When true, allow Unicode → GSM transcoding. |
| message.label | string | No | Override step-level label for this message. |
Examples
Example 1 – Basic template
ViberOtp step uses a basic template (no templateType, or "basic"). Only pin is required for the template.
{
"flow": [
{
"type": "ViberOtp",
"to": ["+306971234567"],
"order": 1,
"ttl": 300,
"failoverOnDelivered": false,
"label": "login-otp",
"senderInfoTrackingId": "0094d198-4dd2-4fb5-b451-d46aca191b27",
"templateId": "0aac888f-2ee2-4112-9659-1755a951966a",
"templateLang": "en",
"otpType": "PRIMARY_ONLY",
"pin": "123456",
"seq": "1234"
},
{
"type": "Sms",
"to": "306971234567",
"order": 2,
"ttl": 600,
"label": "login-otp",
"from": "YourBrand",
"message": {
"body": "Your code is 123456. Valid 10 min.",
"flash": false,
"transcode": true,
"label": "login-sms"
}
}
],
"callback": { "url": "https://your-app.com/otp-events" }
}
Example 2 – Non-basic: business name and validity (hours)
ViberOtp uses templateType: "with_business_and_validity_hours". Required: businessName, validityTime (e.g. "2 hours").
{
"flow": [
{
"type": "ViberOtp",
"to": ["+306971234567"],
"order": 1,
"ttl": 600,
"failoverOnDelivered": false,
"label": "password-reset",
"senderInfoTrackingId": "0094d198-4dd2-4fb5-b451-d46aca191b27",
"templateId": "6c929cef-29b4-4349-bc9d-2a07bdbb6e43",
"templateType": "with_business_and_validity_hours",
"templateLang": "en",
"pin": "784291",
"businessName": "MyApp",
"validityTime": "2 hours",
"seq": "5678"
},
{
"type": "Sms",
"to": "306971234567",
"order": 2,
"ttl": 900,
"label": "password-reset",
"from": "MyApp",
"message": {
"body": "MyApp: Your code is 784291. Valid for 2 hours.",
"flash": false,
"transcode": true
}
}
],
"callback": { "url": "https://your-app.com/otp-events" }
}
Example 3 – Non-basic: pin type and validity
ViberOtp uses templateType: "with_type_and_validity". Required: pinType (e.g. "verification", "login"), validityTime (e.g. "5 minutes").
{
"flow": [
{
"type": "ViberOtp",
"to": ["+306971234567"],
"order": 1,
"ttl": 300,
"failoverOnDelivered": false,
"label": "account-verification",
"senderInfoTrackingId": "0094d198-4dd2-4fb5-b451-d46aca191b27",
"templateId": "60d67b38-b9fb-444a-80e6-754447e010c6",
"templateType": "with_type_and_validity",
"templateLang": "en",
"pin": "901234",
"pinType": "verification",
"validityTime": "5 minutes",
"seq": "9012"
},
{
"type": "Sms",
"to": "306971234567",
"order": 2,
"ttl": 600,
"label": "account-verification",
"from": "YourBrand",
"message": {
"body": "Verification code: 901234. Valid 5 min.",
"flash": false,
"transcode": true
}
}
],
"callback": { "url": "https://your-app.com/otp-events" }
}
Cost – Cost and price are not sent in the request. Routee applies pricing per message. Cost (when available) appears in webhook payloads (price field). For pricing details, see your Routee contract or the Routee platform.
Response – Includes flowId (UUID; use this for tracking), status, and type (e.g. Viber or Sms). The flow array echoes your request; the step that was sent has trackingId (message token from the provider). Use flowId for tracking (GET /otp/failover/{flowId}). Send response status: Succeeded when the flow has only one step (no failover). InProgress when the flow has two or more steps (Viber then SMS, etc.)—the first step was accepted but the flow may still continue (e.g. SMS after Viber Delivered or after Expired). Failed when the send could not be accepted on any channel.
4.2 TTL (required per channel)
Each flow step must include ttl (seconds). It is used for:
- Message validity – Routee uses it as how long the message is valid for that channel.
- Failover timing – For Viber: the service triggers the next channel (e.g. SMS) when Routee reports Expired, Failed, Undelivered, or Unsent. If you set failoverOnDelivered to true on the ViberOtp step, SMS is also sent ttl seconds after Viber reports Delivered. Default failoverOnDelivered is false (failover only on Expired/Failed/Undelivered/Unsent; flow stops on SEEN).
4.3 Failover and delivery statuses
When the next channel is tried (failover)
- Viber → next channel (e.g. SMS): Failover is triggered when Viber reports Expired, Failed, Undelivered, or Unsent. Optionally, set failoverOnDelivered to true to also trigger SMS ttl seconds after Viber reports Delivered. When Viber reports SEEN, failover is not triggered (flow stops).
- SMS → next channel (e.g. Viber): Failover is triggered when SMS reports Undelivered, Failed, or Unsent.
Delivery statuses per channel
| Channel | Statuses | Notes |
|---|---|---|
| SMS | Queued, Sent, Delivered, Undelivered, Failed, Unsent | Delivered, Undelivered, Failed, Unsent are final. Failover is triggered on Undelivered, Failed, Unsent. |
| Viber | QUEUED, DELIVERED, SEEN, EXPIRED, FAILED, UNDELIVERED, UNSENT | Unsent = could not be sent (e.g. insufficient balance); failover is triggered. SEEN stops the flow. |
SMS Undelivered can include a detailedStatus (e.g. Expired, Unknown Number, Carrier Violation). Routee can provide the full list of status values.
Updated 1 day ago
