Portal Community
Approval required: Templates are not immediately usable after creation. Meta's review process typically takes 24–48 hours. Use template/get to poll status or set up a scheduled workflow to check. Only templates with status APPROVED can be used in message/sendTemplate.

When to Use

Configuration

Connection

FieldRequiredDescription
accessTokenRequiredPermanent System User access token with whatsapp_business_management permission. Store in BizFirst Credentials Manager.
phoneNumberIdRequiredUsed to identify the associated WhatsApp Business Account. The API call is made against the Business Account, not the phone number directly.
apiVersionOptionalMeta Graph API version, e.g. v18.0. Defaults to v18.0.

Operation

FieldRequiredDescription
nameRequiredTemplate name. Must be lowercase letters, numbers, and underscores only — no spaces or hyphens (e.g. order_confirmation_v2). Must be unique within the business account.
languageRequiredBCP-47 language code for the template (e.g. en_US, en_GB, es_MX, fr_FR, de_DE, pt_BR).
categoryRequiredTemplate category: AUTHENTICATION (OTP/verification messages), MARKETING (promotional messages, offers), or UTILITY (transactional: order updates, appointment reminders).
componentsRequiredJSON array of component objects defining the template structure. See component schema below.

Components Structure

Each component object has a type field. Supported types:

Sample Configuration

{
  "resource": "template",
  "operation": "create",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "name": "order_shipped_notification",
  "language": "en_US",
  "category": "UTILITY",
  "components": "[{\"type\":\"HEADER\",\"format\":\"TEXT\",\"text\":\"Your Order Has Shipped\"},{\"type\":\"BODY\",\"text\":\"Hi {{1}}, your order #{{2}} has been shipped and will arrive by {{3}}. Track your delivery at: {{4}}\"},{\"type\":\"FOOTER\",\"text\":\"BizFirstAI Commerce\"},{\"type\":\"BUTTONS\",\"buttons\":[{\"type\":\"URL\",\"text\":\"Track Order\",\"url\":\"https://track.example.com/{{1}}\"}]}]"
}

Validation Errors

ErrorCause
accessToken is requiredThe accessToken field is empty or missing.
phoneNumberId is requiredThe phoneNumberId field is empty or missing.
name is requiredThe name field is empty or missing.
language is requiredThe language field is empty or missing.
category is requiredThe category field is empty or missing.
components is requiredThe components field is empty or missing.
invalid_jsonThe components value is not valid JSON. Validate your JSON structure before passing.
132000 (Meta)Template name already exists for this language in the business account.
132005 (Meta)Template body text exceeds the 1024-character maximum.
132012 (Meta)Template contains disallowed content (e.g. phone numbers in MARKETING templates).

Output

Success Port

Fires after Meta accepts the template submission. The template is now in PENDING status and awaiting Meta review. Store the id to poll status later.

FieldTypeDescription
idstringThe newly created template ID. Store this for subsequent template/get, template/update, and template/submitForReview calls.
templateStatusstringInitial status after creation — always "PENDING".
statusstring"created" on success.
errorCodestringEmpty on success.
errorMessagestringEmpty on success.
rawResponsestringFull raw JSON response from Meta.

Error Port

Fires when Meta rejects the template or the submission fails.

FieldTypeDescription
statusstring"failed" or "error".
errorCodestringMeta error code or BizFirst internal code.
errorMessagestringHuman-readable rejection reason.
rawResponsestringRaw API error JSON for diagnostics.

Sample Output

{
  "id": "987654321098765",
  "templateStatus": "PENDING",
  "status": "created",
  "errorCode": null,
  "errorMessage": null,
  "rawResponse": "{\"id\":\"987654321098765\",\"status\":\"PENDING\"}"
}

Expression Reference

ValueExpressionNotes
Template ID{{ $output.createTemplate.id }}Store in a database record. Use for subsequent get/update/submitForReview calls.
Template status{{ $output.createTemplate.templateStatus }}Always "PENDING" immediately after creation. Poll via template/get.
Operation status{{ $output.createTemplate.status }}"created" on success — confirms the API call succeeded.
Error code{{ $output.createTemplate.errorCode }}Non-null on error port. Check for 132000 (duplicate name) to handle gracefully.

Node Policies & GuardRails

Policy AreaRecommendation
Review timelineMeta's review process takes 24–48 hours on average but can take up to 7 days. Do not create templates and immediately attempt to send — build a review-wait loop into your workflow.
Name uniquenessTemplate names must be unique per language. Check for existing templates with template/getMany before creating to avoid 132000 errors.
Category selectionChoosing the wrong category is the most common rejection reason. Use UTILITY for transactional messages, MARKETING only for promotional content, and AUTHENTICATION strictly for OTP flows.
Variable placeholder formatVariables in BODY text must use the {{1}}, {{2}} format — numbered sequentially from 1. Named variables are not supported.
Credential permissionsThe access token must have the whatsapp_business_management permission scope. A token with only whatsapp_business_messaging scope will fail with a 200 permissions error.
Error port handlingAlways connect the error port and log the full rawResponse — Meta's rejection messages contain actionable guidance on why a template was rejected.

Examples

Create a UTILITY Order Confirmation Template

{
  "resource": "template",
  "operation": "create",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "name": "order_confirmation_v1",
  "language": "en_US",
  "category": "UTILITY",
  "components": "[{\"type\":\"BODY\",\"text\":\"Thank you for your order, {{1}}! Your order #{{2}} for {{3}} has been confirmed. Expected delivery: {{4}}.\"}]"
}

A new tenant onboarding workflow creates this standard order confirmation template as part of setup. After creation, a downstream node stores the returned id in the tenant settings table. A scheduled daily job polls template/get until status reaches APPROVED, then marks the template as ready in the configuration.

Create a MARKETING Template with Quick Reply Buttons

{
  "resource": "template",
  "operation": "create",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "name": "summer_sale_2024",
  "language": "en_US",
  "category": "MARKETING",
  "components": "[{\"type\":\"HEADER\",\"format\":\"IMAGE\",\"example\":{\"header_handle\":[\"{{ $input.bannerMediaHandle }}\"]}},{\"type\":\"BODY\",\"text\":\"Hi {{1}}, our Summer Sale starts tomorrow! Enjoy {{2}}% off everything. Shop now before stocks run out!\"},{\"type\":\"FOOTER\",\"text\":\"Reply STOP to unsubscribe\"},{\"type\":\"BUTTONS\",\"buttons\":[{\"type\":\"QUICK_REPLY\",\"text\":\"Shop Now\"},{\"type\":\"QUICK_REPLY\",\"text\":\"View Deals\"},{\"type\":\"QUICK_REPLY\",\"text\":\"Unsubscribe\"}]}]"
}

A campaign preparation workflow creates this template 2 weeks before the sale. The image header references a banner image already uploaded via media/upload. The template ID is stored and the workflow polls for approval daily until ready.

Create a Multi-Language Template Set

// Loop node iterates over: ["en_US", "es_MX", "fr_FR", "de_DE"]
{
  "resource": "template",
  "operation": "create",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "name": "appointment_reminder",
  "language": "{{ $loop.currentItem }}",
  "category": "UTILITY",
  "components": "{{ $input.componentsForLocale[$loop.currentItem] }}"
}

A localisation workflow creates the same template in 4 languages by looping through a language list. Each language's component JSON is stored in a componentsForLocale lookup object populated by a translation service upstream. All four template IDs are collected and stored for each locale's send pipeline.