# Get an email template version

`GET /v1/email/templates/{template_ref}/versions/{version_id}`

Returns a single version of an email template:

- Its lifecycle metadata (`status`, `version_number`, `published_at`).
- The content it froze in every language.
- The `variables` that content expects at send time.

Use [List email template versions](/docs/api/reference/list-email-template-versions) to enumerate the draft and published versions. [Roll back an email template](/docs/api/reference/rollback-email-template) makes an earlier published version live again. Returns a `404 Not Found` error if the template or version does not exist in the workspace.

## Code samples

### CLI

```sh
bird email templates versions get <template-ref> <version-id>
```

### cURL

```sh
curl -X GET "https://us1.platform.bird.com/v1/email/templates/{template_ref}/versions/{version_id}" \
  -H "Authorization: Bearer $TOKEN"
```

## Example response `200`

```json
{
  "id": "emv_01krdgeqcxet5s7t44vh8rt9mg",
  "template_id": "emt_01krdgeqcxet5s7t44vh8rt9mg",
  "status": "published",
  "variables": [
    {
      "type": "code"
    }
  ],
  "default_language": "pt-BR",
  "updated_by": {
    "id": "usr_01krdgeqcxet5s7t44vh8rt9mg",
    "type": "user"
  }
}
```

## Path parameters

- `template_ref` (string): The template's id (`emt_…`) or slug. On read, a built-in `system` template's `bird_` slug also resolves here, to its one permanently published version. Discarding a draft requires a workspace template, because a `system` template has no draft and returns `404` `not_found_error`.
- `version_id` (string)

## Response body

- `id` (string, required): Template version ID.
- `template_id` (string, required): The template this version belongs to.
- `version_number` (nullable integer): Sequential published-version number (1, 2, 3…). Null while the version is a draft.
- `status` (string, required)

  Whether this version is still being edited or has been published. It records
  the version's publication history: a version that a later one replaced stays
  `published`. The template's `live_version_id` names the version a send
  resolves to now.

  `archived` is reserved and no version carries it yet. Version retirement will
  produce it, so it is declared here ahead of that feature: a client written
  against this list today keeps working when the first archived version arrives,
  rather than the value's arrival being a breaking change.

  Possible values: `draft`, `published`, `archived`
- `revision` (integer, required): The version's revision counter.
- `variables` (array of object, required)

  Every variable this version's content uses. You supply a value for each of them when you send.

  The list combines all the languages, because languages do not have to use the same variables: if the English body uses `discount_code` and the French body uses `shipping_date`, both appear here. Send a value for every variable in the list rather than only the ones you expect the language you are sending to use. A language that does not use a variable ignores the value you sent for it, and a variable the sent language does use but you left out is rejected with a `422` naming it.

  Variables under the reserved `bird.` namespace are not listed here. We fill those in ourselves from the recipient's contact record.
- `variables.key` (string, required): The key this slot is filled by. On email and SMS it is the key you set in the send's `parameters` object. On WhatsApp it is the `name` you repeat on the matching parameter inside `components`, or, for a template whose placeholders are positional, the position itself as `1`, `2` and so on.
- `variables.type` (string, required)

  The value type this slot accepts. SMS templates use the typed slots (`code`, `amount` and the rest), each of which rejects a value that does not match its `constraint`. Email and WhatsApp templates use `text`, which accepts any value. Open enum: treat an unrecognized value as a future type rather than an error.

  Possible values (may grow over time): `code`, `ttl`, `count`, `ref`, `date`, `date_time`, `amount`, `currency`, `text`
- `variables.required` (boolean, required): Whether the send must supply this variable. Omitting a required value returns `422` on email, SMS, and WhatsApp sends.
- `variables.constraint` (string, required): A plain-language description of what values this variable accepts.
- `variables.sensitive` (boolean): Whether this slot's value is kept out of durable storage. A sensitive slot's rendered value never appears in message content read back through the API: a stand-in placeholder is stored instead.
- `languages` (object, required): The content this version holds, keyed by language tag in BCP-47 form such as `en` or `pt-BR`. Publishing freezes every language together, so a version shows exactly what it would send in each of them. On a published version this is the send content.
- `default_language` (string, required): The language this version treats as its default: the one a send uses when it names none, and the last resort when a requested language is not available.
- `created_at` (string, required): When this version was created.
- `published_at` (nullable string): When this version was published, or null if it has not been published.
- `updated_by` (nullable object): Who last saved this version: a member's own session, an OAuth token delegated from one, or a workspace API key. Publishing freezes a version, so on a published one this is whoever published it. Null means no actor is on record: a built-in template, which is code-defined rather than stored, or a version last saved by an API key before this field existed. Every other version has one, even when its display_name could not be resolved (a member whose account is gone, say).
- `updated_by.id` (string, required): Actor identifier.
- `updated_by.type` (string, required)

  Who or what performed the action: `user` for a member's own session, `oauth_token` for a token issued to a caller on a member's behalf, `api_key` for a workspace API key, `system` for our own automation, `sso` for an organization's SSO connection, and `service_account` for a workspace's connected Integration acting with no member behind it. Open enum: new actor types may be added over time, so treat any unrecognized value as a future type rather than an error.

  Possible values (may grow over time): `user`, `api_key`, `oauth_token`, `system`, `sso`, `service_account`
- `updated_by.display_name` (nullable string): The label the actor is shown under: typically a member's name or email address, or the API key's name. Null when it could not be resolved.

## Related resources

- [How to build an email template](/learn/email/how-to-build-an-email-template) (video)
- [Email templates](/products/email/templates) (product)
- [Build your first integration](/learn/paths/integration) (course)
- [Email templates](/docs/guides/email/templates) (docs)

[Get an implementation brief](/learn/workspace?topic=email-templates)
