Sign inGet Started

Submit a template version for review

POST
/v1/whatsapp/templates/{template_ref}/versions/{version_id}/submit
const draftId = "wav_01krdgeqcxet5s7t44vh8rt9mg";
const check = await bird.whatsapp.templates.versions.submit("order_update", draftId, {
  validate_only: true,
});
for (const problem of check.errors) console.log(problem.language, problem.field, problem.message);
if (check.valid) {
  const submitted = await bird.whatsapp.templates.versions.submit("order_update", draftId);
  console.log(submitted.version?.id);
}
Réponse200
{
  "errors": [
    {
      "language": "pt-BR",
      "field": "components[2].cards[0].components[1].example_parameters[0].url",
      "code": "E15025",
      "message": "A body block needs text."
    }
  ],
  "version": {
    "id": "wav_01krdgeqcxet5s7t44vh8rt9mg",
    "template_id": "wat_01krdgeqcxet5s7t44vh8rt9mg",
    "version_number": 4,
    "submitted_at": "2026-07-20T11:04:00Z",
    "variables": [
      {
        "type": "code"
      }
    ],
    "languages": {
      "en": {
        "status": "approved",
        "components": [
          {
            "type": "body",
            "text": "Your verification code is {{1}}.",
            "example_parameters": [
              {
                "type": "text",
                "text": "123456"
              }
            ]
          }
        ]
      }
    },
    "created_at": "2026-07-20T10:31:00Z"
  },
  "next": [
    {
      "kind": "operation"
    }
  ]
}

Validates the template draft before freezing it. If validation fails, the API returns 200 OK with every problem across all languages and creates no version. If validation passes, the API freezes an immutable version and returns 202 Accepted. Only the languages whose content differs from their approved copy are sent to Meta and marked pending; the rest carry their existing verdict forward untouched, so a version whose languages are all unchanged comes back already settled. A language an earlier version carried but the draft dropped is deleted at Meta in the background. It is absent from the new version, so it has no pending state. The version becomes live when any language is approved, and no replacement draft opens automatically.

Set validate_only: true to run the same checks without freezing or submitting a version. Local validation cannot predict Meta's decision. A 202 Accepted response confirms the version was frozen and accepted. Poll the version or the template's pending_version_id for the verdicts on whichever languages it marked pending.

Paramètres

template_refstring

Template ID (wat_ prefix) or slug. A value that parses as a valid ID resolves by ID; any other value resolves as a slug.

version_idstring

ID of the template version (wav_ prefix), as returned by the version list.

Corps de la requête

validate_only
boolean

Check the draft without submitting it. Every language is checked and every problem reported, but nothing is frozen and nothing is sent to WhatsApp. A clean result does not guarantee WhatsApp approval: WhatsApp offers no way to ask in advance, so it can still refuse a submission these checks passed. Use a different idempotency key for the validation and the submission. Reusing one key with different request bodies is rejected.

Contenu de la réponse

valid
boolean
obligatoire

Whether the version passed every check.

errors
array of object
obligatoire

Every problem found across every language. One round trip identifies all problems. Empty when valid is true.

Afficher les attributs enfants
version
nullable object

The version this submit froze, or null when nothing was frozen: a check run, or a submit that found problems.

Afficher les attributs enfants
version.id
string
obligatoire

Stable Bird identifier for the version.

version.template_id
string
obligatoire

The template this version belongs to.

version.version_number
nullable integer

The version's sequence number, assigned when it is submitted. Null on a draft, which has not been submitted and has no place in the sequence yet.

version.submitted_at
nullable string
obligatoire

When this version was submitted to Meta. Null on a draft, which has not been submitted, and null for a built-in template's version, which Bird ships already approved rather than submitting on your behalf.

version.variables
array of object

The variable slots this version's content fills in from the values you supply when sending. Combined across every language, because languages need not declare the same slots: if the English body uses first_name and the French one uses last_name, both appear here. A template with named parameters keys them by name; a positional one keys them by their {{n}} position, as 1, 2 and so on. Supply the slots the language you send declares, by these keys in template.parameters or through components.

Afficher les attributs enfants
version.variables.key
string
obligatoire

The key this slot is filled by. When system is true it is the reserved bird key or a dotted path beneath it, such as bird.contact.first_name, and naming it in a send is rejected. Otherwise, on email and SMS it is the key you set in the send's parameters object, and on WhatsApp the key in the send's template.parameters, or the name on the matching parameter inside components. A WhatsApp template whose placeholders are positional uses the position itself as 1, 2 and so on, and values with no placeholder use fixed keys: header_url, header_filename, header_location and code, plus button_url (or button_url_1, button_url_2 for a carousel card) for a url button whose suffix is numbered.

version.variables.type
string
obligatoire

The value type this slot accepts. Each typed slot rejects a value that does not match its constraint. Built-in SMS templates use typed slots (code, amount and the rest); domain is a lowercase DNS domain name such as example.com, which the verification templates fill to bind a passcode to a website, and app_hash is an 11-character Android SMS Retriever app hash such as FA+9qCX9VSu, which they fill to bind it to an Android app. Apple Messages templates type a variable from its content: the field it fills (url, image, timestamp, location, timezone) or the formatting filter applied to it (date, date_time, amount, currency). Email and workspace SMS templates use text. WhatsApp templates use text, plus url for a media header's file and location for a location header. A location value is an object with latitude and longitude, and optionally name and address. On Apple Messages, name becomes the location's title and address is not shown. Workspace SMS parameters must be scalar values.

Possible values (may grow over time): code, ttl, count, ref, date, date_time, amount, currency, domain, app_hash, url, image, timestamp, timezone, location, text

version.variables.required
boolean
obligatoire

Whether the send must supply this variable. Omitting a required value returns 422 on every channel. On Apple Messages, a later time slot's start that is used nowhere else is optional: a send that omits it drops that slot. Always false when system is true, because you do not supply that slot's value.

version.variables.constraint
string
obligatoire

A plain-language description of what values this variable accepts. When system is true it names where Bird takes the value from instead, because there is no value for you to send.

version.variables.sensitive
boolean

Whether this slot requires redacted message history. Published email template sends that store recipient snapshots reject sensitive inputs before acceptance. Other channels retain their own sensitive-input delivery and retention rules.

version.variables.system
boolean

Whether the value comes from Bird rather than from the send. Absent means false. System slots are identified by the reserved bird key or a dotted path beneath it. They appear on email templates, and on WhatsApp templates whose parameter bindings read contact data; every SMS slot is yours to fill. A draft can also name a reserved key no Bird value fills, including bird itself: constraint says so, and publishing that draft is rejected.

version.languages
object
obligatoire

This version's content, keyed by BCP-47 language tag, with what its submission did with each language.

version.created_at
nullable string
obligatoire

When the version was opened. Null for a built-in template's version, which Bird ships rather than stores.

next
array of object

What to do next with this outcome. Present on reads that compute it: an empty list means there is nothing to do, and the field is absent entirely on responses that do not report next actions.

A failed check routes back to the languages that need an edit; a clean one routes to the real submit, and then to polling the template for WhatsApp's verdicts.

Afficher les attributs enfants

Poursuivez avec la documentation, les guides et les exemples sur ce sujet.