Skip to main content

Zalo onboarding: connect your Official Account and send ZNS templates

This guide takes a Zalo channel from nothing to a working production integration: Official Account provisioning, the template-only send, inbound replies, and delivery statuses. The field and error reference lives on the Zalo channel page — this guide is the ordered path you run the first time. For the region-wide survey of LINE, WeChat, KakaoTalk, and Zalo, see APAC channels onboarding. Zalo is a beta channel. The send and receive paths are wired end to end, but the Official Account, template approvals, and the ZNS access token are provisioned off-Orbit in the Zalo for Developers console.
  1. Create a Zalo Official Account (OA) in the Zalo for Developers console. The OA is the sender identity on every ZNS notification.
  2. Register your ZNS templates in the same console and wait for Zalo approval. Each approved template receives a template id — that id is what template_name references on a send. An edited template is a new approval.
  3. Generate the OA access token (OAuth oauth/access_token grant) and paste it in Orbit under Settings → Channels → Zalo. The token is short-lived; rotate it through Zalo’s grant before it expires. Orbit stores it encrypted at rest and never echoes it back through any API response.
Consent alignment: ZNS notifications are numbers the end user shared with your business. Record consent (and the opt-out signal from the OA subscription list) in your own contact model before the first send, and route failures into your suppression and opt-out list so the next campaign skips opted-out recipients. Tenant-owned controls — quiet hours, consent, suppression — apply to Zalo exactly as to SMS; the template approval above is the only extra gate this channel adds. Until credentials are connected, every send fails closed with CHANNEL_NOT_CONFIGURED (503).

2. Template-based send — no free-form body

ZNS is template-only: a business sends a pre-approved notification template to a customer’s phone number. The send body on POST /api/v1/messages/zalo carries to and template_name, plus an optional flat template_params map filling the template’s named variables. There is no free-form body field — a send without an approved template_name is rejected with VALIDATION_ERROR (422).
202 Accepted — the message is queued; the terminal delivered / failed state arrives later on the delivery-status webhook. Carry your own correlation key in metadata — it is echoed back on those events. The sender is resolved automatically from the OA credentials connected to your organization; you never pass an access token on the request. The direct endpoint is capped at 80 requests/minute per organization — stage bulk template sends through the Campaigns API with channel: "zalo", where message_template and variables map to template_name and template_params.

3. Samples: curl, Node.js, Python

4. Inbound replies and delivery statuses

There is no Zalo webhook to register. Inbound replies and ZNS delivery callbacks land on your account’s standard webhooks — subscribe under Settings → Webhooks:
  • Inbound replies arrive on message.received with channel: "zalo", folded onto the normalized inbound event envelope. Branch on data.normalized.kind === "inbound" instead of parsing event strings.
  • Delivery status advances the outbound message to delivered / failed, reconciled by the tracking id Orbit mints per send. Your metadata map rides along on the event.
Verify the X-Orbit-Signature header before trusting any event — Verify webhook signatures.

5. Common errors

See also