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 fieldTypeRequiredDescription
flowarrayYesOrdered steps (ViberOtp and/or Sms). Each step has type, to, order, and channel-specific fields.
callbackobjectNo{ "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)

FieldTypeRequiredDescription
typestringYes"ViberOtp" or "Sms".
tostring or arrayYesRecipient(s) in E.164 format (e.g. "306912345671" or ["+306912345671"] for ViberOtp).
orderintegerYesStep order in the flow (1, 2, …). Must be unique.
ttlintegerYesTime to live in seconds (required per channel; used for message validity and failover timing).
labelstringNoCampaign 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

FieldRequiredTypeDescription
senderInfoTrackingIdYesstringRoutee Viber OTP sender identifier (from your sender registration).
templateIdYesstringRoutee Viber OTP template UUID.
pinYesstringOTP code (4–10 characters).
templateTypeRequired for non-basic templatesstringTemplate 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.
businessNameRequired if templateType is with_business_name, with_business_and_validity_hours, or with_reasonstringBusiness/platform name.
validityTimeRequired if templateType is with_validity, with_type_and_validity, or with_business_and_validity_hoursstringValidity time (e.g. minutes or hours as per template).
pinTypeRequired if templateType is with_type or with_type_and_validitystringPin type (e.g. "verification", "login").
actionNameRequired if templateType is with_actionstringAction/platform description (e.g. "account verification").
codeReasonRequired if templateType is with_reasonstringReason for the code (e.g. "you requested a password reset").
failoverOnDeliveredNobooleanWhen 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.
templateLangNostringLanguage code (e.g. "en"). Default: "en".
otpTypeNostringe.g. "PRIMARY_ONLY".
seqNostringUnique sequence number for the request.

Sms step – additional fields

FieldTypeRequiredDescription
fromstringNoRoutee SMS sender ID (alphanumeric or numeric). If omitted, the service default is used.
messageobjectYesMust contain at least body.
message.bodystringYesSMS text.
message.flashbooleanNoWhen true, send as flash SMS (display only).
message.transcodebooleanNoWhen true, allow Unicode → GSM transcoding.
message.labelstringNoOverride 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

ChannelStatusesNotes
SMSQueued, Sent, Delivered, Undelivered, Failed, UnsentDelivered, Undelivered, Failed, Unsent are final. Failover is triggered on Undelivered, Failed, Unsent.
ViberQUEUED, DELIVERED, SEEN, EXPIRED, FAILED, UNDELIVERED, UNSENTUnsent = 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.


What’s Next