Callbacks (Webhook)

Webhook callbacks for Standard and Transactional Failover — payload shape, strategies, retry policy, and flowKind.

Callbacks are HTTP POST webhooks Routee sends to your URL when a Failover flow completes a step or reaches a terminal outcome. They apply to Standard and Transactional Failover (POST /failover and POST /failover/transactional).

Failover OTP uses a separate service. OTP webhooks use optional callback.url on create and a different payload shape — see Send a Failover OTP message.


Enable callbacks on create

Include a callback object when you create a flow:

{
  "flow": [ ... ],
  "callback": {
    "strategy": "OnStep",
    "url": "https://your-server.com/failover-webhook"
  }
}
FieldRequiredValues
callback.urlYesHTTPS (or HTTP) endpoint that accepts POST with Content-Type: application/json
callback.strategyYesOnStep or OnCompletion

Both strategies use the same JSON payload shape (below). They differ only in when Routee sends it.


When callbacks are sent

The Failover service publishes a callback task when:

  1. A step completes and failover advances to the next channel (FlowStepChangedEvent), or
  2. The flow reaches a terminal outcome — Succeeded or Failed (FlowStatusChangedEvent).
StrategySent when
OnStepOn every step transition and when the flow reaches Succeeded or Failed. Mid-flow payloads usually have root status: "InProgress".
OnCompletionOnly when the flow reaches a terminal status — Succeeded or Failed. No callback while the flow is still progressing through channels.

What is in messages[]: Only completed steps at the time of the callback. The service loads tracking from Routee for each completed step and sorts messages by order, then by type (SMS parts by part, etc.). Steps still in progress are not included until they complete.

If Routee tracking cannot be loaded for a step, a minimal message object is still sent (ids, to, order, failoverOnStatuses, and type) so your webhook is not empty.


HTTP delivery

ItemDetail
MethodPOST
HeadersContent-Type: application/json
BodyJSON object (same structure as GET /failover/tracking/{trackingId} for Standard / Transactional)
SuccessYour endpoint should respond HTTP 200 OK promptly (Routee callbacks platform uses a short HTTP client timeout, typically 2 seconds)
RetriesOn failure, the Routee callbacks service retries with increasing delays (see below)

Example payload (Standard — Viber then SMS)

{
  "trackingId": "30830fad-21ed-49b0-89d0-bbada2fd5640",
  "flowKind": "standard",
  "messages": [
    {
      "type": "Viber",
      "trackingId": "0a047b46-a4dd-4ca8-b817-a6a134dd1234",
      "to": "+306912345678",
      "from": "Routeetest",
      "country": "GR",
      "ttl": 10,
      "expireOnDelivery": false,
      "expiredOnDeliveryAt": null,
      "status": {
        "name": "DELIVERED",
        "reason": {
          "detailedStatus": "Delivered",
          "description": "The message was delivered to its recipient."
        },
        "updatedDate": "2019-07-05T10:28:44.996Z"
      },
      "body": {
        "text": "This is a test, please ignore!",
        "imageUrl": "https://example.com/image.png",
        "action": {
          "caption": "Go",
          "targetUrl": "https://www.routee.net/"
        }
      },
      "label": "labelName",
      "failoverOnStatuses": ["EXPIRED", "FAILED", "UNDELIVERED"],
      "order": 1,
      "inboundUrl": "https://your-server.com/inbound",
      "price": 0.035,
      "createdAt": "2019-07-05T10:28:44.566Z"
    },
    {
      "type": "Sms",
      "messageId": "82a91dc3-e842-41eb-86e5-07d55eb51234",
      "smsId": "1274d238-38b7-4c56-b49a-9b70d25c1234",
      "to": "+306912345678",
      "from": "Routee",
      "country": "GR",
      "operator": "Vodafone",
      "ttl": 15,
      "status": {
        "name": "Delivered",
        "reason": {
          "detailedStatus": "Delivered",
          "description": "The SMS was sent and it was delivered to its recipient."
        },
        "updatedDate": "2019-07-05T10:28:49Z"
      },
      "body": "Hello from failover",
      "price": 0.036,
      "label": "labelName",
      "order": 2,
      "part": 1,
      "parts": 1,
      "latency": 4,
      "failoverOnStatuses": ["Undelivered", "Failed"],
      "createdAt": "2019-07-05T10:28:45.227Z"
    }
  ],
  "terminationChannel": "Sms",
  "status": "Succeeded",
  "statusCode": null,
  "totalPrice": 0.071,
  "originatingService": "failover",
  "applicationId": "5b223c27e4b04b9cdaa71234",
  "createdAt": "2019-07-05T10:28:44.44Z",
  "updatedAt": "2019-07-05T10:28:49.634Z"
}

Notes on the example

  • Root status in callbacks is InProgress, Succeeded, or Failed — not Queued (callbacks fire after the flow has started processing).
  • originatingService is always the lowercase string failover.
  • statusCode is present only when root status is Failed — values "0""3" (see Failover Statuses).
  • Each message includes type: Sms, Viber, or Voice.
  • Viber: body.action (not viberAction); ttl is in minutes (converted from seconds in tracking). Optional body.viberFile, body.viberVideo for rich content.
  • SMS: body is a string. Multipart SMS may produce multiple messages[] entries with the same order and different part / smsId.
  • Transactional flows (flowKind: transactional): Viber entries use templateId, templateLang, templateParams, deliveryScope, seq instead of promotional body.text / media.

Payload reference — root level

KEYDESCRIPTION
trackingIdFailover flow tracking id (same as create response).
flowKindstandard (POST /failover) or transactional (POST /failover/transactional). Omitted on older flows → treat as standard.
messagesArray of completed step messages, sorted by order.
terminationChannelChannel of the last executed step when the flow completed: Sms, Viber, or Voice. May be null if not set.
statusInProgress, Succeeded, or Failed.
statusCodeOnly when status is Failed. String "0""3" — see Failover Statuses.
totalPriceSum of price on messages in this payload (where price is available).
originatingServiceAlways failover.
applicationIdRoutee application id that created the flow.
createdAtFlow creation time (ISO 8601).
updatedAtTime of the flow state update that triggered this callback (ISO 8601).

Payload reference — all message types

KEYDESCRIPTION
typeSms, Viber, or Voice.
toRecipient.
fromSender id (SMS/Voice) or sender name (Viber).
countryRecipient country (ISO 3166-1 alpha-2) when available.
orderStep order in the flow (1, 2, …).
failoverOnStatusesStatuses that trigger the next step for this channel (echoed from your request; casing may vary by channel).
statusDelivery status object for this step.
status.nameChannel-specific status name — see Failover Statuses.
status.reasonOptional. SMS/Viber: object with detailedStatus, description. Voice: reason and description are strings on status.
status.updatedDateLast status change (ISO 8601).
priceCost of this message when available.
createdAtWhen this channel tracking was created (ISO 8601).

Viber only

KEYDESCRIPTION
trackingIdViber message tracking id.
ttlTTL in minutes (0.5–1440; default 10).
bodyContent object: text, imageUrl, action, viberFile, viberVideo.
body.action.captionButton label (1–30 characters).
body.action.targetUrlButton URL.
inboundUrlInbound Viber messages callback URL if set on create.
labelOptional message label.
expireOnDeliveryIf true, Delivered may become Expired after TTL with no Seen.
expiredOnDeliveryAtWhen expire-on-delivery fired (ISO 8601).
templateIdTransactional only — BM template UUID.
templateLangTransactional only — template language.
templateParamsTransactional only — placeholder map.
deliveryScopeTransactional onlyPRIMARY_DEVICE or ALL_DEVICES.
seqTransactional only — sequence number from request.

SMS only

KEYDESCRIPTION
bodySMS text (string, not an object).
messageIdSMS part / tracking id for this part.
smsIdParent SMS message id (shared across parts).
partPart number (multipart).
partsTotal parts.
operatorMobile operator when available.
latencyDelivery latency in milliseconds.
ttlTTL in minutes (1–1440; default 1200).
labelOptional label.

Voice only

KEYDESCRIPTION
messageIdVoice message id.
conversationTrackingIdVoice conversation tracking id.
status.reasonExtra reason (string).
status.descriptionHuman-readable description (string).
durationCall duration (seconds).
chargeIntervalBilling interval (seconds).
answeredByMachine detection result when enabled (e.g. HUMAN).
fileURLReserved; typically null in current implementations.
failoverOnStatusese.g. Busy, NoAnswer (defaults) — may include Failed, Unsent, Terminated if configured.

Callback strategy (summary)

StrategyUse when
OnStepYou want updates after each channel attempt (including mid-flow InProgress) and on final outcome.
OnCompletionYou only care about the final Succeeded / Failed result.

Callback retry policy

Your endpoint must respond with HTTP 200 OK within the callbacks platform HTTP timeout (typically 2 seconds). Otherwise Routee closes the connection and retries delivery via the shared callbacks service.

Documented retry schedule (up to 12 retries over 24 hours):

RetryDelay after previous attempt
1st30 sec
2nd1 min
3rd2 min
4th5 min
5th10 min
6th15 min
7th30 min
8th1 hour
9th2 hours
10th4 hours
11th8 hours
12th24 hours

After retries are exhausted, delivery stops for that callback chain. Design your handler to be idempotent — the same flow update may be POSTed more than once.

Secure your endpoint — Serve callbacks over HTTPS and include a hard-to-guess secret in the callback URL path or query string. Validate it on every request.


Related documentation

TopicPage
Flow & channel statuses, statusCodeFailover Statuses
Which API to useFailover endpoints
Tracking API (same payload shape)Resource Overview
Transactional createHow to send a transactional Failover message