---
title: "Update an email template"
method: PATCH
path: "/v1/email/templates/{template_ref}"
tags: ["email-templates"]
---

# Update an email template

`PATCH /v1/email/templates/{template_ref}`

## Request

- Base URL: `https://us1.platform.bird.com`
- URL: `https://us1.platform.bird.com/v1/email/templates/{template_ref}`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `bird_session`

Updates a template's metadata and draft settings, such as its name or default language. Only the fields you send are changed.

Content is not edited here: save a language on the draft version instead.

Send the draft `revision` you last read. If someone else changed the draft first, including by saving a language, the revision is stale and the request returns a conflict so you can reload and retry.

## Headers

- `Idempotency-Key` string
- `X-Workspace-Id` string
- `X-Organization-Id` string

## Request body

- EmailTemplateUpdate: Partial update of a template's metadata and draft settings. Only the fields you send are changed. The rest are left as-is. Include the draft `revision` you last read so concurrent edits are detected. Content is not here: save a language on the draft version to change what the template says.
  - `revision` integer, required: The draft revision you last read (from the template's `revision` field). A stale value returns a conflict so you can reload and retry.
  - `name` string: New display name, in free text. The slug stays fixed at creation, so renaming the template does not break whatever refers to it by slug or id.
  - `description` string, nullable: What the template is for, in your own words. Send `null` to clear it.
  - `default_language` string: A language tag in BCP-47 form, for example `en` or `pt-BR`.
  - `on_missing_language` 'fallback' | 'fail': What a send or a preview does when it asks for a language the template cannot serve. `fallback` serves the closest match instead. It tries a broader form of the same language first, so a request for `pt-BR` can be served by a stocked `pt`, and then the template's default language. A send never fails because a language is missing. `fail` rejects the send rather than serving a different language, for content where sending the wrong language is worse than not sending at all. It matches the requested tag or a broader form of it and refuses a sibling variant, so `pt-BR` is never served by `pt-PT`. A send that names no language still uses the default language. The default is per channel and stated on each channel's own field, because what a wrong-language send costs differs. Where every language is separately reviewed and separately priced, falling back silently would send content the recipient did not expect at a rate the sender did not choose.
  - `language_source_required` boolean: Whether a send has to name a language. Turning it on rejects a send that names none instead of serving the default language. A broadcast must select a template language when this is set.

## Response `200`

The template with the updated metadata and draft settings.

- EmailTemplate
  - `editor_url` string, uri: Optional link to open the saved draft in the browser editor, in its default language. Absent for built-in templates.
  - `id` string, required
  - `workspace_id` string, required
  - `slug` string, required: A template's slug: what you send it by, for example `welcome-email`. Email and SMS slugs stay fixed after creation. WhatsApp slugs can change only before the first submission. A slug can contain lowercase letters, numbers, hyphens, and underscores, has to start and end with a letter or a number, and can be up to 63 characters long.
  - `name` string, required: The template's display name, shown wherever the template is listed. You can change it any time. It defaults to the slug if you do not set one.
  - `description` string, nullable, required: What the template is for, in your own words. Null if you have not set one.
  - `scope` 'system' | 'workspace', required: Whether the template is one of our built-in templates (`system`) or one your workspace created (`workspace`).
  - `status` 'draft' | 'pending' | 'active' | 'rejected' | 'inactive', required: Where the template stands as a whole. The same five states on every channel. - `draft`: nothing has ever gone live. - `pending`: nothing is live and at least one language is in review. - `active`: at least one language is live, so something can be sent. - `rejected`: it was reviewed and every language was refused. - `inactive`: nothing is live and nothing is in review, so content was withdrawn or was blocked before anything went live. A template with one language live is `active` even while another is still drafted or refused. Read `languages` for the state of each language and its reason. Which values a channel reports follows its review model. A channel whose content a third party reviews uses all five. On email and SMS, where content goes live on publish, a template is `draft`, `active` or `inactive`, and `pending` and `rejected` are reserved for the review stage coming to both, so a template reaching either is not a breaking change.
  - `category` 'transactional' | 'marketing', required: Whether the template is for `transactional` email or `marketing` email.
  - `source` string, required: The authoring format the template is written in, fixed at creation. `html` is finished markup you provide, optionally personalized with Liquid.
  - `theme` string, required: The visual theme a built-in template is designed in. Each of the catalog's five themes ships its own set of eight emails, and the sets overlap only partly, so the theme is what you choose between once you know which email you want. Only our built-in `system` templates have one.
  - `draft_version_id` string, required
  - `live_version_id` string, required
  - `published_version_id` string, required
  - `revision` integer, nullable, required: The draft's revision counter. Send it back on the next update to detect concurrent edits. Null for a built-in `system` template, which is unversioned.
  - `languages` object, required: Every language this template has, keyed by language tag in BCP-47 form such as `en` or `pt-BR`, each with its state. One read tells you which languages are live and which have unpublished edits, without fetching any content. Content is not here: read a version's languages for that, one language at a time.
  - `default_language` string, required: A language tag in BCP-47 form, for example `en` or `pt-BR`.
  - `available_languages` LanguageTag[], required: The languages this template currently supports for sending, as BCP-47 tags. Empty until the template is published, because sends serve published content. The set may shrink for reasons other than editing, so read it rather than assuming it matches what was published. A built-in `system` template has no publish step and always reports its one language.
  - `on_missing_language` 'fallback' | 'fail', required: What a send or a preview does when it asks for a language the template cannot serve. `fallback` serves the closest match instead. It tries a broader form of the same language first, so a request for `pt-BR` can be served by a stocked `pt`, and then the template's default language. A send never fails because a language is missing. `fail` rejects the send rather than serving a different language, for content where sending the wrong language is worse than not sending at all. It matches the requested tag or a broader form of it and refuses a sibling variant, so `pt-BR` is never served by `pt-PT`. A send that names no language still uses the default language. The default is per channel and stated on each channel's own field, because what a wrong-language send costs differs. Where every language is separately reviewed and separately priced, falling back silently would send content the recipient did not expect at a rate the sender did not choose.
  - `language_source_required` boolean, required: Whether a send has to name a language. When true, a send that names none is rejected instead of being served the default language. A broadcast must select a template language when this is set.
  - `last_submitted_at` string, date-time, nullable, required: When this template was last submitted. Null if it never has been. Submitting is the only thing that moves this timestamp: rolling back changes which version is live without counting as a submit, so this keeps reporting the last real submit. Read it alongside `languages`, which says where each language stands.
  - `created_at` string, date-time, nullable, required: When the template was created. Null for a built-in `system` template.
  - `updated_at` string, date-time, nullable, required: When the template was last modified. Null for a built-in `system` template.

## Other responses

- `400`: Bad request
- `401`: Authentication required
- `403`: Insufficient permissions
- `404`: Resource not found
- `409`: Resource conflict
- `422`: The request has invalid field values, violates a business rule, or carries a query parameter the endpoint does not declare. Field validation errors use `type: validation_error` and include the affected fields in `details`. Business-rule errors identify the failed rule in `type`.
- `429`: Rate limit exceeded
- `500`: Internal server error
- `503`: The service is temporarily unavailable. If `Retry-After` is present, wait for that delay before retrying; otherwise, retry with exponential backoff. Reuse the same idempotency key and request when retrying a mutation.

---

[API](https://skmtc.dev/messagebird/apis/bird-api.md) · [All operations](https://skmtc.dev/messagebird/apis/bird-api/llms.txt) · [OpenAPI document](https://skmtc.dev/messagebird/apis/bird-api/revisions/6dfce1179799?raw)
