This guide is for developers building integrations on Routee. It describes the REST endpoints to create and manage Rakuten Viber Business Messages (BM) transactional templates and to send approved templates (including OTP).
For why templates are required, content and OTP rules, moderation timelines, and FAQs, see the customer guide.
| You are looking for… | Document |
|---|---|
| Business context and compliance (e.g. July 2026) | Customer guide |
| Endpoint URLs, JSON fields, and responses | This reference |
Tracking GET and delivery callbackUrl payloads | Tracking and delivery callbacks |
Base URL and authentication
| Item | Value |
|---|---|
| Production base URL | https://connect.routee.net |
| Authentication | OAuth 2.0 Bearer token in the Authorization header |
| Format | Authorization: Bearer <access_token> |
Your access token must belong to a Routee account that is allowed to use Viber. Routee resolves which account and which senders you may use from the token and from the parameters you pass (for example senderInfoTrackingId).
Permissions and errors
Your Routee API credentials (application / OAuth setup) must include:
- Viber-related OAuth scopes — typically
viberorall(as configured for your integration). - Rights to manage templates — create, read, and delete transactional templates for your Viber sender(s).
- Rights to send — permission to send Viber messages for the same account.
If the token is missing, invalid, or not allowed to perform the operation, the API usually returns HTTP 403. If a resource (for example account or sender context) cannot be resolved, you may receive HTTP 404.
Quick start — typical flow
- Authenticate — Obtain a valid Bearer token with Viber access.
- Pick a sender — Use the Routee tracking id of your Viber sender (
senderInfoTrackingId) when you create templates and when you send. - Create a template —
POST /viber/transactional/templates?senderInfoTrackingId=…and wait until the template is approved in Routee (see the customer guide for moderation and optional notifications). - Send — Call
POST /viber/transactional/messagesfor every approved template (transactional or OTP category). There is no separate greenfield/viber/transactional/otp. UsetemplateId,templateLang,templateParams, and optionaldeliveryScope. OTP-category templates must includepinintemplateParams. - Optional webhooks — You may set a
callbackUrlon the template for moderation status updates, and acallbackUrlon each send for delivery status. Those callbacks use different JSON payloads (see Moderation callback).
flowchart LR
A[Create template] --> B[Wait until approved]
B --> C[Send template message]
C --> D[Optional delivery callback]
Request conventions
| Topic | Guidance |
|---|---|
| JSON | Use Content-Type: application/json on all bodies. |
| Supported fields only | For POST /viber/transactional/messages, use only the fields described below. Extra or unknown top-level JSON properties may be rejected. |
| Device targeting | Use deliveryScope: PRIMARY_DEVICE (default) or ALL_DEVICES. Invalid values may return HTTP 400. |
| Naming | Use deliveryScope on these endpoints; do not send numeric transactionalSendTypeCode in the JSON — it is not part of this API. |
Transactional templates
All paths below are relative to the base URL, for example:
https://connect.routee.net/viber/transactional/templates
List, read, create, update webhook, delete
| Method | Path | Query parameters | Response (success) |
|---|---|---|---|
| GET | /viber/transactional/templates | Optional: pageSize, lastServiceId, lastTemplateId, senderInfoTrackingId | 200 — list of templates |
| GET | /viber/transactional/templates/{templateId} | — | 200 — one template |
| POST | /viber/transactional/templates | Required query: senderInfoTrackingId | 200 — created template |
| PATCH | /viber/transactional/templates/{templateId} | — | 200 — updated template metadata |
| DELETE | /viber/transactional/templates/{templateId} | — | 200 — confirmation payload |
Create template — JSON body (POST)
POST)| Field | Type | Required | Description |
|---|---|---|---|
category | string | Yes | OTP or Transactional. OTP templates must include {{pin}} in the text (see customer guide). |
params | array | Yes | Declares placeholders. May be an empty array for a fully static template. See Parameters below. |
locales | array | Yes | At least one language version of the text. See Locales below. |
varExample | array | Yes | Example values shown during moderation. Empty if params is empty. See Examples below. |
callbackUrl | string (URL) | No | HTTPS URL where Routee will POST JSON when the template’s moderation status changes (guide — lifecycle callback). |
moderationNotifyEmail | string | No | Optional email for Routee moderation status notifications when the template lifecycle changes (approved / rejected). If omitted, Routee may use account notification settings when available. See customer guide §8.2. |
Parameters (params items)
params items)| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name of the variable (matches {{name}} in the template text). |
type | string | Yes | Use TEXT. |
Locales (locales items)
locales items)| Field | Type | Required | Description |
|---|---|---|---|
lang | string | Yes | Language code (ISO 639-1, e.g. en). Must match the templateLang you send later. |
template | string | Yes | Message text including {{placeholders}}. Must comply with Viber / Routee rules. |
Examples (varExample items)
varExample items)| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Same as in params. |
example | string | Yes | Sample value for reviewers. |
Example body:
{
"category": "Transactional",
"params": [{ "name": "user_name", "type": "TEXT" }],
"locales": [
{ "lang": "en", "template": "Hello {{user_name}}, your appointment is confirmed." }
],
"varExample": [{ "name": "user_name", "example": "Alex" }]
}
Update moderation webhook only (PATCH)
PATCH)This request only updates Routee settings for your template moderation webhook. It does not change the template text sent to Viber.
- Send
callbackUrlwith an HTTPS URL, or"callbackUrl": nullto remove the stored URL. - You may use the alternative property name
lifecycleCallbackUrlinstead ofcallbackUrl(same meaning). - The body must include
callbackUrlorlifecycleCallbackUrlas a key. An empty body{}or omitting both keys returns HTTP 400 on greenfield paths (/viber/transactional/templates/...). Legacy/viber/bm/transactional-templates/...PATCH remains backward compatible (empty body may no-op).
Send transactional template messages
Paths are under:
https://connect.routee.net/viber/transactional/
| Method | Path | Purpose |
|---|---|---|
| POST | /viber/transactional/messages | Send any approved BM transactional template (transactional or OTP category). No free-form marketing body; content comes from the template. OTP-category: templateParams must include pin. |
There is no greenfield POST /viber/transactional/otp. Legacy POST /viber/otp on Routee Connect remains for older integrations.
POST /viber/transactional/messages — request body
POST /viber/transactional/messages — request body| Field | Type | Required | Description |
|---|---|---|---|
senderInfoTrackingId | string | Yes | Your Viber sender (Routee tracking id). |
to | string | Yes | Recipient in E.164 format with leading +. |
templateId | string | Yes | Id of an approved template. |
templateLang | string | Yes | Language code matching the template (e.g. en). |
templateParams | object | No* | Map of placeholder name → value (TEXT, max 25 chars each, no URLs, no file-extension-like values such as test.pdf). For OTP templates, include pin. See Send-time validation. Omit or {} only when the template has no variables. |
deliveryScope | string | No | PRIMARY_DEVICE or ALL_DEVICES. Default: PRIMARY_DEVICE. |
seq | number | No | Optional partner correlation id. If omitted, Routee assigns a value (millisecond timestamp) before the message is queued; the assigned or supplied value is returned in the HTTP 200 response and echoed on tracking GET / delivery callbacks as transactionalTemplate.seq. |
ttl | integer | No | Time-to-live / validity window where applicable. |
inboundUrl | string | No | HTTPS callback for inbound replies, where supported. |
callbackUrl | string | No | HTTPS URL for delivery status callbacks for this message. |
label | string | No | Optional label for reporting. |
multipleSinglesMessageId | string | No | Optional batch id for grouped reporting. |
sessionMessage | boolean | No | Session message flag where supported. |
Example — non-OTP
POST https://connect.routee.net/viber/transactional/messages
Authorization: Bearer <access_token>
Content-Type: application/json
{
"senderInfoTrackingId": "your-viber-sender-tracking-id",
"to": "+972500000000",
"templateId": "YOUR-APPROVED-TEMPLATE-ID",
"templateLang": "en",
"templateParams": {
"user_name": "Alex",
"order_id": "4829"
},
"deliveryScope": "PRIMARY_DEVICE"
}
Example — OTP-category template
{
"senderInfoTrackingId": "your-viber-sender-tracking-id",
"to": "+972500000000",
"templateId": "YOUR-APPROVED-OTP-TEMPLATE-ID",
"templateLang": "en",
"templateParams": { "pin": "482910", "minutes": "5" },
"deliveryScope": "PRIMARY_DEVICE",
"ttl": 86400
}
POST /viber/transactional/messages — response (success)
POST /viber/transactional/messages — response (success)HTTP 200 means the message was accepted for processing, not that the handset has received it yet.
The JSON includes fields such as:
| Field | Description |
|---|---|
trackingId | Routee tracking id for this send (use for support and status). |
deliveryScope | PRIMARY_DEVICE or ALL_DEVICES as applied. |
seq | Correlation id (yours if supplied, otherwise assigned by Routee). |
to, from | Recipient and sender identity as resolved by Routee. |
status | Initial status object for the message. |
price | Charged amount for this request where applicable. |
Other fields (label, sessionMessage, callbackUrl, ttl, etc.) may appear depending on your request and product behaviour.
Delivery status: tracking GET and callbackUrl
callbackUrlPoll GET /viber/tracking/{trackingId} or receive delivery callbacks on the optional callbackUrl from the send request.
Full field reference, examples, and backward-compatibility notes:
Tracking and delivery callbacks (for public Routee / readme.io documentation).
messageKind and transactionalTemplate (summary)
messageKind and transactionalTemplate (summary)Template-based sends add a discriminator and a nested metadata block. Values depend on the send path and stored record type — see the tracking guide for full examples.
| Field | Typical values | When present |
|---|---|---|
messageKind | transactional_template | Greenfield POST /viber/transactional/messages and legacy template sends on POST /viber |
otp | Legacy POST /viber/otp; tracking GET when the stored record is flagged otp: true | |
transactionalTemplate | Object with templateId, templateLang, deliveryScope, seq | Any send that used an approved template id |
transactionalTemplate.templateParams | Placeholder map; pin masked as `*`** | Tracking GET only — never in delivery callbacks |
Shared transactional block
When the send used an approved BM template (POST /viber/transactional/messages, or legacy template fields on POST /viber / POST /viber/otp), responses include:
| Field | Tracking GET | Delivery callback | Notes |
|---|---|---|---|
messageKind | ✓ | ✓ | transactional_template or otp |
transactionalTemplate.templateId | ✓ | ✓ | |
transactionalTemplate.templateLang | ✓ | ✓ | |
transactionalTemplate.deliveryScope | ✓ | ✓ | PRIMARY_DEVICE or ALL_DEVICES |
transactionalTemplate.seq | ✓ | ✓ | Always set for template sends (partner value or Routee-assigned) |
transactionalTemplate.templateParams | ✓ | ✗ | GET only; pin is masked (***) |
createdAt | ✓ | ✓ | ISO-8601 timestamp |
templateId (top-level) | ✓ | — | Same as transactionalTemplate.templateId (portal compatibility) |
Legacy rich single and campaign messages omit messageKind and transactionalTemplate. Existing fields (message, body.text, campaignTrackingId, etc.) are unchanged.
Callback status shape (unchanged): status.name, status.updatedDate. Tracking GET uses status.status, status.date.
Template sends on callback: empty body is omitted (no "body": {}). Legacy single/campaign callbacks still include body when present.
Example delivery callback:
{
"trackingId": "304177c4-2478-4c49-bcea-3b6cede1b064",
"to": "+306973359331",
"status": {
"name": "DELIVERED",
"updatedDate": "2026-05-20T05:45:13.606Z"
},
"messageKind": "transactional_template",
"transactionalTemplate": {
"templateId": "2c017482-2f44-41d6-adad-2d6af725fdbe",
"templateLang": "en",
"deliveryScope": "PRIMARY_DEVICE",
"seq": 1747719911946
}
}
Send-time validation (before queue)
Routee validates templateLang and templateParams against the approved template before the message is queued. Invalid requests fail immediately with HTTP 400 instead of failing later at Viber with status 39.
Error response shape
| Field | Value |
|---|---|
| HTTP status | 400 |
code | 400019029 |
developerMessage | Human-readable summary (single issue or joined list) |
validationIssues | Array of { "code": "…", "message": "…" } |
Example — file-extension-like parameter:
{
"code": "400019029",
"developerMessage": "Parameter document_name must not look like a file name or extension (e.g. test.pdf).",
"validationIssues": [
{
"code": "PARAM_CONTAINS_FILE_EXTENSION",
"message": "Parameter document_name must not look like a file name or extension (e.g. test.pdf)."
}
]
}
Common validationIssues codes
validationIssues codes| Code | Meaning |
|---|---|
TEMPLATE_LANG_REQUIRED | templateLang missing |
TEMPLATE_LANG_MISMATCH | templateLang does not match template locale |
MISSING_PARAM | Required placeholder missing or blank |
UNKNOWN_PARAM | Extra key not declared on template |
PARAM_VALUE_TOO_LONG | Value longer than 25 characters |
PARAM_CONTAINS_URL | URL-like content in a TEXT parameter |
PARAM_CONTAINS_FILE_EXTENSION | File-extension-like fragment (e.g. test.pdf) |
OTP_PIN_REQUIRED | OTP-category template without pin |
These checks are in addition to auth (403), unknown template projection (404 / not approved), and Viber partner codes (7, 38, 39) after the send reaches the provider.
Moderation callback (callbackUrl on the template)
callbackUrl on the template)If you set callbackUrl when creating (or updating) a template, Routee will POST to that HTTPS URL when the template’s moderation status changes (for example pending → approved or rejected).
- Content-Type:
application/json - Payload — Routee sends a focused object, for example:
| Field | Always present? | Meaning |
|---|---|---|
templateId | Yes | Template id. |
templateStatus | Yes | Routee status, e.g. PENDING_MODERATION, APPROVED, REJECTED. |
templateBody | Sometimes | Template text snapshot if available. |
variables | Sometimes | Ordered list of placeholder names (not the values used at send time). |
rejectionReason | Sometimes | Reason when rejected. |
Do not depend on extra fields such as serviceId, eventId, or vendor-specific raw codes unless Routee documents them for your integration.
Important: This payload is not the same as delivery callbacks you configure on POST /viber/transactional/messages. Use separate URLs unless you deliberately route both types through your own gateway and distinguish them there.
Moderation email (internal AMQP → Notifications)
Routee also sends moderation lifecycle emails when moderationNotifyEmail is set (or via Profile notification settings). The internal VIBER_BM_TRANSACTIONAL_TEMPLATE_LIFECYCLE AMQP payload (api → notifications) includes:
| Field | When present | Used in email |
|---|---|---|
templateId | Always | Template ID row |
templateName | When Routee can resolve display text | Template Name row |
statusNote | Always for approve/pending; on reject when detail exists | Moderation Note row |
rejectionReason | Rejected events | Fallback for statusNote in Notifications when statusNote is absent |
viberEventType | Always | Drives status label (1000 / 1001 / 1002) |
templateName is derived from the stored template body snapshot or the first locale returned by Viber Partners API. statusNote defaults to “Your template has been approved and is ready to send.” on approval when Viber sends no moderation text.
Common issues
| Situation | Typical result |
|---|---|
| Invalid OAuth or no Viber permission | 403 |
| Unknown account / resource | 404 |
PATCH greenfield template without callbackUrl / lifecycleCallbackUrl | 400 |
Invalid templateLang or templateParams at send time | 400 — 400019029 + validationIssues |
| Template or send rejected by Routee / Viber validation | 400 / 422 (depends on the case) |
| Send rejected with Viber partner codes (7, 38, 39, …) | See guide §7.3 |
Partner error codes can change; treat tables as indicative and verify against the latest Viber / Routee documentation you receive.
Postman and samples
Routee provides a Postman collection with ready-made calls for transactional templates and sends (collection name along the lines of Routee Viber BM Transactional). Use the copy supplied in your Routee developer / onboarding materials, or ask your Routee contact for the latest export.
