---
title: "Roll back an email template"
method: POST
path: "/v1/email/templates/{template_ref}/versions/{version_id}/rollback"
tags: ["email-templates"]
---

# Roll back an email template

`POST /v1/email/templates/{template_ref}/versions/{version_id}/rollback`

## Request

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

Makes an earlier published version the live version used by sends, and replaces the draft with that version's content so editing continues from it. The change is immediate. No new version is created, and the version history is unchanged. Include the draft `revision` you last read, so the request is rejected with a conflict if someone else changed the draft first. The draft's current content is replaced. Rolling back to the currently live version is allowed and resets the draft to it. Only published versions can be rolled back to.

## Headers

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

## Request body

- EmailTemplateRollback: Parameters for rolling a template back to an earlier published version. Rolling back also replaces the draft with that version's content, so you have to pass `revision`, the revision number of the draft you last read. If the draft has changed since you read it, that revision number is now stale, and the rollback fails with a conflict instead of overwriting the newer draft. Read the draft again to get its current revision, and try the rollback again.
  - `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.

## Response `200`

The template, with its draft reset to the restored version's content.

- 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)
