# List an SMS template's versions

`GET /v1/sms/templates/{template_ref}/versions`

Returns a cursor-paginated version history, newest first. Each entry is shallow and names its variables and languages. Read a version item or one of its languages to retrieve text. A built-in template exposes its current catalogue content as one synthetic published version.

## Code samples

### TypeScript

```ts
for await (const version of bird.smsTemplates.versions.list("bird_otp_verification")) {
  console.log(version.id, version.version_number);
}
```

### Python

```py
for version in client.sms_templates.versions.list("bird_otp_verification"):
    print(version.id, version.version_number)
```

### Go

```go
for version, err := range client.SmsTemplates.Versions.List(context.Background(), "bird_otp_verification", bird.SmsTemplatesVersionsListParams{}) {
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(version.Id, *version.VersionNumber)
}
```

### PHP

```php
foreach ($bird->smsTemplates->versions->list('bird_otp_verification') as $version) {
    echo $version->getId(), ' ', $version->getVersionNumber(), "\n";
}
```

### CLI

```sh
bird sms templates versions list <template-ref>
```

### cURL

```sh
curl -X GET "https://us1.platform.bird.com/v1/sms/templates/{template_ref}/versions" \
  -H "Authorization: Bearer $TOKEN" \
  --url-query "sort=created_at" \
  --url-query "order=desc" \
  --url-query "limit=25"
```

## Example response `200`

```json
{
  "data": [
    {
      "id": "smv_01krdgeqcxet5s7t44vh8rt9mg",
      "template_id": "smt_01krdgeqcxet5s7t44vh8rt9mg",
      "version_number": 1,
      "status": "published",
      "revision": 1,
      "variables": [
        {
          "key": "order_number",
          "type": "text",
          "required": true,
          "constraint": "A string, number, or boolean."
        }
      ],
      "default_language": "en",
      "created_at": "2026-09-10T09:00:00Z",
      "published_at": "2026-09-10T09:00:00Z",
      "available_languages": [
        "en"
      ]
    }
  ],
  "next_cursor": "eyJ2IjoxLCJzIjoiXCIyMDI2LTA1LTI1VDE0OjAzOjEwWlwiIiwiaSI6IjAxOTJmM2IxLTRjN2UtN2EyYi05ZDYxLThmM2E1YzJlN2I0MCJ9",
  "prev_cursor": null,
  "refresh_cursor": "eyJ2IjoxLCJzIjoiXCIyMDI2LTA1LTI1VDE2OjQyOjAxWlwiIiwiaSI6IjAxOTJmM2IxLTllMDQtN2NkMy1iODE3LTJhNmY0ZDFjOGUwOSJ9"
}
```

## Path parameters

- `template_ref` (string): The template's ID (`smt_…`) or slug.

## Query parameters

- `sort` (string)

  Field to sort by.

  Possible values: `created_at`
- `order` (string)

  Sort direction. Defaults to `desc`, which sorts from newest to oldest or largest to smallest, depending on the selected sort field.

  Possible values: `asc`, `desc`
- `limit` (integer): Maximum number of items to return per page.
- `starting_after` (string): Cursor from the `next_cursor` field of a previous list response. Returns items immediately after the cursor position in the current sort order.
- `ending_before` (string): Cursor from the `prev_cursor` or `refresh_cursor` field of a previous list response. Returns items immediately before the cursor position in the current sort order. `prev_cursor` returns the preceding page. `refresh_cursor` anchors at the first row of that response, which on a newest-first sort is how to fetch the items that have appeared since.

## Response body

- `data` (array of object, required): One page of the template's versions, newest first.
- `data.id` (string, required): Template version ID.
- `data.template_id` (string, required): The template this version belongs to.
- `data.version_number` (nullable integer, required): Sequential publication number. Null for the draft; a built-in template reports 1.
- `data.status` (string, required)

  Whether the version is the editable draft or published. Published workspace versions are immutable and remain `published` after a later version goes live. A built-in template's synthetic published version projects the current catalogue entry.

  Possible values: `draft`, `published`
- `data.revision` (integer, required): The version's revision counter.
- `data.variables` (array of object, required): Variables inferred from the version's text and shared by each language.
- `data.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.
- `data.variables.type` (string, required)

  The value type this slot accepts. Built-in SMS templates use typed slots (`code`, `amount` and the rest), each of which rejects a value that does not match its `constraint`. Email, WhatsApp and workspace SMS templates use `text`. Workspace SMS parameters must be scalar values. 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`
- `data.variables.required` (boolean, required): Whether the send must supply this variable. Omitting a required value returns `422` on email, SMS, and WhatsApp sends.
- `data.variables.constraint` (string, required): A plain-language description of what values this variable accepts.
- `data.variables.sensitive` (boolean): Whether this slot's value is redacted from stored message content. A placeholder replaces the sensitive value in message history; transport queues can still carry the text needed for delivery.
- `data.default_language` (string, required): The language this version treats as its default.
- `data.available_languages` (array of string, required): Languages this version contains, without their text.
- `data.created_at` (nullable string, required): When the version was created. Null for a built-in template's synthetic version.
- `data.published_at` (nullable string, required): When the version was published. Null for the draft and for a built-in template's synthetic version.
- `next_cursor` (nullable string, required): Cursor for the next page. Pass back as `starting_after` to advance forward. `null` when no next page exists.
- `prev_cursor` (nullable string, required): Cursor for the previous page. Pass back as `ending_before` to step backward. `null` when no previous page exists.
- `refresh_cursor` (nullable string, required): Refresh anchor, the first row of this response. Pass back as `ending_before` to fetch what precedes it in the current sort order. On a newest-first sort those are the items that have appeared since; on any other sort they are the items that sort earlier, so refreshing such a list means re-fetching it instead. Non-`null` whenever `data` is non-empty; `null` only on an empty page. Distinct from `prev_cursor`.

## Related resources

- [Should I use a Bird SDK or call the API directly?](/explained/platform/should-i-use-an-sdk-or-call-the-api-directly) (answer)
- [Build your first integration](/learn/paths/integration) (course)
- [Send your first email](/docs/get-started/send-your-first-email) (docs)

[Get an implementation brief](/learn/workspace?topic=api-basics)
