Skip to main content

Create ZBS Template

This API allows you to create a Zalo Business Solution (ZBS) Template with full display content and dynamic parameters.

Usage flow:

  1. Create the template with this API — the template is saved with status DRAFT and the response returns its _id.
  2. Publish the template with the Publish ZBS Template API to submit it to Zalo for review (PENDING_REVIEW).
  3. Once Zalo approves it (ENABLE), the template can be used to send messages.
Template content is described with contentBlocks

Starting from the latest version, the display content of a template is declared through the contentBlocks array (paragraph, table, voucher, rating) instead of the previous paragraphs and tables fields.


Endpoint

🔗Endpoint Staging
Endpoint
POST https://staging-manage.api.miniai.vn/api/external/zns-template/create
🔗Endpoint Production
Endpoint
POST https://manage-api.miniap.vn/api/external/zns-template/create

Authentication

Every request must include your API key in the header:

HeaderValueRequired
x-api-keyminiai-partner <YOUR_API_KEY>Bắt buộc
Content-Typeapplication/jsonBắt buộc
No need to send shopId

The shop is identified from the API key itself, so the system assigns shopId to the template for you. You do not need to (and cannot) pass shopId in the request body.


Parameters (Request Body)

General information

FieldTypeRequiredDescription
oaIdstringBắt buộcID of the Zalo OA used to send messages. Required before the template can be published.
namestringBắt buộcTemplate name (for internal management).
descriptionstringTùy chọnShort description of the template's purpose.
titlestringBắt buộcTitle shown in the message. Dynamic parameters such as <customer_fullname> can be inserted.
tag"1" | "2" | "3"Bắt buộcTemplate content level — see Template level.
templateTypecustom | voucher | ratingBắt buộcTemplate type — see Template type.
imageTypelogo | imageBắt buộcHeader image style: use a logo or a banner image.
logoLightstringTùy chọnLogo URL for light background. Required when imageType = logo (validated on publish).
logoDarkstringTùy chọnLogo URL for dark background. Required when imageType = logo.
imagesstring[]Tùy chọnList of image URLs. At least one image is required when imageType = image.
contentBlocksobject[]Bắt buộcMessage body content — see contentBlocks.
buttonsobject[]Bắt buộcList of buttons, maximum 3 — see buttons.
paramsobject[]Bắt buộcDynamic parameter declarations — see params.
voucherobjectCó điều kiệnRequired when templateType = voucher — see Voucher template.
ratingobjectCó điều kiệnRequired when templateType = rating — see Rating template.
isCustomParamsbooleanBắt buộctrue if you declare the parameters in params yourself; false to use the system's default parameter set.
notestringTùy chọnNote sent to Zalo's review team (explaining the message's use case).
No need to send status

Templates are always created with status DRAFT, even if you include status in the request. Status changes happen through the Publish ZBS Template API.

Template level (tag)

Zalo classifies messages by content level; the level affects review policy and message pricing.

tagLevelSuitable content
"1"TransactionAccount verification, OTP, order/transaction confirmation, balance changes…
"2"Customer careLoyalty point updates, policy updates, opinion surveys, birthday greetings…
"3"Post-saleNew product/service announcements, discount codes and promotions, renewal invitations…

Template type (templateType)

ValueNameDescription
customCustom messageFree-form message: transaction notices, OTP, reminders…
voucherVoucher templateSend a discount code / voucher with conditions and expiry.
ratingRating templateCollect customer feedback after using a product/service.

Message content (contentBlocks)

contentBlocks is an array of content blocks, rendered in the exact order you declare them.

FieldTypeRequiredDescription
idstringBắt buộcUnique identifier of the block (a UUID you generate).
typeparagraph | table | voucher | ratingBắt buộcContent block type.
valuestringCó điều kiệnText content — used by paragraph blocks. Parameters such as <order_code> can be inserted.
rowsobject[]Có điều kiệnTable rows — used by table blocks.
voucherobjectCó điều kiệnVoucher information — used by voucher blocks.
ratingobjectCó điều kiệnRating information — used by rating blocks.

Table rows (rows)

FieldTypeRequiredDescription
labelstringBắt buộcLabel shown on the left (e.g. Order code).
keystringBắt buộcValue shown on the right; use <parameter_name> to insert a dynamic parameter.
rowTypenumberTùy chọnRow color effect, defaults to 0.

rowType values:

rowTypeMeaning
0No effect
1Success (green)
2Update (blue)
3Warning (yellow)
4Error (red)
5Basic

Dynamic parameters (params)

Every parameter used in title, a paragraph, or rows must be declared in params.

FieldTypeRequiredDescription
keystringBắt buộcParameter name, without the <> brackets (e.g. order_code).
labelstringBắt buộcDisplay name of the parameter in the editor.
techSettingstringBắt buộcZalo's technical data type — determines review rules and maximum length.
maxLengthnumberBắt buộcMaximum length of the submitted value, matching the techSetting.
sampleValuestringBắt buộcSample value used by Zalo for preview and review.

techSetting values and their maxLength:

techSettingData typemaxLength
"1"Customer name30
"2"Phone number15
"3"Address200
"4"Code (order code, customer code…)30
"5"Custom label30
"6"Transaction status30
"7"Contact information50
"8"Gender / Title5
"9"Product name / Brand200
"10"Quantity / Amount20
"11"Time20
"12"OTP10
"13"URL200
"14"Currency (VND)12
"15"Bank transfer note90
Pick the right techSetting

A parameter without techSetting causes the publish template request to fail with 400. Choosing the wrong technical type (e.g. using Custom label for an amount) is a common reason Zalo rejects a template.


Buttons (buttons)

A maximum of 3 buttons per template.

FieldTypeRequiredDescription
labelstringBắt buộcText shown on the button.
typestringBắt buộcButton action type — see the table below.
valuestringBắt buộcDestination value of the action (URL, phone number, Mini App ID…). Can be an empty string for actions that need no value.
typeAction
"1"Go to the business page
"2"Call (value is a phone number)
"3"Go to the OA information page
"4"Go to the business's Zalo Mini App
"5"Go to the business's app page
"6"Go to the product distribution page
"7"Go to another website / Zalo Mini App
"8"Go to another app
"9"Go to a business article
"10"Go to an app-download call-to-action landing page

Voucher template

When templateType = voucher, the top-level voucher field is required:

FieldTypeDescription
codestringVoucher code (usually a dynamic parameter, e.g. <voucher_code>).
titlestringProgram / offer name.
conditionstringApplicable conditions.
startDatestringStart date of validity.
expiryDatestringExpiry date.
Displayed content lives in contentBlocks

The top-level voucher (and rating) field is used for input validation only — it is not stored and is not returned in the response. What actually renders in the message is the voucher / rating block inside contentBlocks, so declare matching values in both places and read the values back from contentBlocks.

Rating template

When templateType = rating, the top-level rating field is required and contains an items array (at least one element):

FieldTypeDescription
starnumberStar count for that answer scenario (1–5).
titlestringTitle shown for that star level.
questionstringFollow-up question for the customer.
answersstring[]List of suggested answers.
thanksstringThank-you message after the customer rates.
descriptionstringAdditional description.

Example Request (cURL)

curl -X POST 'https://manage-api.miniap.vn/api/external/zns-template/create' \
-H 'x-api-key: miniai-partner <YOUR_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"oaId": "2288954399991473926",
"name": "Order confirmation",
"description": "Order confirmation notice for the customer",
"title": "Hello <customer_fullname>,",
"tag": "1",
"templateType": "custom",
"imageType": "logo",
"logoLight": "https://cdn.miniap.vn/zns/logo-light.png",
"logoDark": "https://cdn.miniap.vn/zns/logo-dark.png",
"isCustomParams": true,
"contentBlocks": [
{
"id": "10c8db12-7f66-4b53-a79c-22b5a01dac49",
"type": "paragraph",
"value": "Thank you for your order. Your order has been confirmed."
},
{
"id": "6f2b0a54-1f5a-4f0f-9a52-0f5b2b6c7d10",
"type": "table",
"rows": [
{ "label": "Order code", "key": "<order_code>", "rowType": 0 },
{ "label": "Status", "key": "<order_status>", "rowType": 1 }
]
}
],
"buttons": [
{ "label": "View order", "value": "https://manage.miniai.vn/orders", "type": "1" }
],
"params": [
{ "key": "customer_fullname", "label": "Customer fullname", "techSetting": "1", "maxLength": 30, "sampleValue": "Nguyễn Văn A" },
{ "key": "order_code", "label": "Order code", "techSetting": "4", "maxLength": 30, "sampleValue": "DH123456" },
{ "key": "order_status", "label": "Order status", "techSetting": "6", "maxLength": 30, "sampleValue": "Confirmed" }
]
}'
Do not send shopId

The shopId is resolved from your API key on the server, so it is omitted here. The full field-by-field body is described in the examples below.


Request Body examples

{
"oaId": "2288954399991473926",
"name": "Order confirmation",
"description": "Order confirmation notice for the customer",
"title": "Hello <customer_fullname>,",
"tag": "1",
"templateType": "custom",
"imageType": "logo",
"logoLight": "https://cdn.miniap.vn/zns/logo-light.png",
"logoDark": "https://cdn.miniap.vn/zns/logo-dark.png",
"images": [],
"isCustomParams": true,
"contentBlocks": [
{
"id": "10c8db12-7f66-4b53-a79c-22b5a01dac49",
"type": "paragraph",
"value": "Thank you for shopping with us. Your order has been confirmed."
},
{
"id": "6f2b0a54-1f5a-4f0f-9a52-0f5b2b6c7d10",
"type": "table",
"rows": [
{ "label": "Order code", "key": "<order_code>", "rowType": 0 },
{ "label": "Status", "key": "<order_status>", "rowType": 1 },
{ "label": "Total payment", "key": "<order_price>", "rowType": 0 }
]
}
],
"buttons": [
{
"label": "View order",
"value": "https://manage.miniai.vn/orders",
"type": "1"
}
],
"params": [
{
"key": "customer_fullname",
"label": "Customer fullname",
"techSetting": "1",
"maxLength": 30,
"sampleValue": "Nguyễn Văn A"
},
{
"key": "order_code",
"label": "Order code",
"techSetting": "4",
"maxLength": 30,
"sampleValue": "DH123456"
},
{
"key": "order_status",
"label": "Order status",
"techSetting": "6",
"maxLength": 30,
"sampleValue": "Confirmed"
},
{
"key": "order_price",
"label": "Order price",
"techSetting": "14",
"maxLength": 12,
"sampleValue": "1500000"
}
],
"note": "Message sent when an order is confirmed"
}

Response

{
"template": {
"name": "Order confirmation",
"description": "Order confirmation notice for the customer",
"oaId": "2288954399991473926",
"tag": "1",
"templateType": "custom",
"imageType": "logo",
"title": "Hello <customer_fullname>,",
"contentBlocks": [
{
"id": "10c8db12-7f66-4b53-a79c-22b5a01dac49",
"type": "paragraph",
"value": "Thank you for shopping with us. Your order has been confirmed."
},
{
"id": "6f2b0a54-1f5a-4f0f-9a52-0f5b2b6c7d10",
"type": "table",
"rows": [
{ "label": "Order code", "key": "<order_code>", "rowType": 0 },
{ "label": "Status", "key": "<order_status>", "rowType": 1 },
{ "label": "Total payment", "key": "<order_price>", "rowType": 0 }
]
}
],
"buttons": [
{
"label": "View order",
"value": "https://manage.miniai.vn/orders",
"type": "1"
}
],
"params": [
{
"key": "customer_fullname",
"label": "Customer fullname",
"techSetting": "1",
"maxLength": 30,
"sampleValue": "Nguyễn Văn A"
},
{
"key": "order_code",
"label": "Order code",
"techSetting": "4",
"maxLength": 30,
"sampleValue": "DH123456"
},
{
"key": "order_status",
"label": "Order status",
"techSetting": "6",
"maxLength": 30,
"sampleValue": "Confirmed"
},
{
"key": "order_price",
"label": "Order price",
"techSetting": "14",
"maxLength": 12,
"sampleValue": "1500000"
}
],
"logoDark": "https://cdn.miniap.vn/zns/logo-dark.png",
"logoLight": "https://cdn.miniap.vn/zns/logo-light.png",
"images": [],
"note": "Message sent when an order is confirmed",
"shopId": "64204a17a5a97a86f12e1f0a",
"status": "DRAFT",
"isSync": false,
"isCustomParams": true,
"_id": "68c8ee675f8f83fc813e7830",
"createdAt": "2025-09-16T04:58:15.668Z",
"updatedAt": "2025-09-16T04:58:15.668Z",
"id": "68c8ee675f8f83fc813e7830"
}
}

Common errors

CodeCause
400Missing required field, wrong data type, invalid techSetting, or more than 3 buttons
401Missing x-api-key header, wrong miniai-partner prefix, or invalid API key
429Request limit exceeded (see the Rate limit section below)
500System error

Rate limit

100 requests / minute

Each shop may call at most 100 requests per minute across the entire External API. Exceeding the limit returns a 429.

Next step

Use the _id from the response as the template_id when calling the Publish ZBS Template API, then look it up again with Get template detail.