Skip to navigation
AuthenticationMigrate to the v2 application token API

Migrate to the v2 application token API

The v1 application token endpoints are deprecated. They keep working until they’re removed, and every new application token feature, such as assigning a role to a token, is available in v2 only.

The v1 endpoints for managing application tokens (/api/v1/application_token) stop working on June 1, 2027. Move your integration to v2 before then.

This guide lists what you have to change in your integration to move from v1 to v2.

Your existing application tokens keep working. You don’t have to recreate them, and authenticating with a token through POST /api/v1/authenticate doesn’t change. The migration only affects code that creates, lists, updates, or deletes application tokens.

Endpoint mapping

Taskv1v2
List tokensGET /api/v1/application_tokenGET /api/v2/application_token
Get a tokenNot availableGET /api/v2/application_token/{id}
List token statusesNot availableGET /api/v2/application_token/status
Create a tokenPOST /api/v1/application_tokenPOST /api/v2/application_token
Rename a tokenPATCH /api/v1/application_token/{id}PATCH /api/v2/application_token/{id}
Revoke a tokenPATCH /api/v1/application_token/{id} with a statusDELETE /api/v2/application_token/{id}

Summary of breaking changes

ChangeWhat breaks if you don’t update
Status IDs changeCode that compares status.id misreads every token
Revoking moves to DELETERevoke requests fail or leave the token active
expiry_date is requiredCreating a token without an expiry date fails
roles is requiredCreating a token without a role fails
Stricter token namesNames longer than 64 characters or with other characters are rejected
IP restrictions are an arrayA token created with ip instead of ip_restrictions has no IP restriction
Lists return active tokens onlyRevoked tokens are missing from the list
300 active tokens per WorkspaceCreating a token beyond the limit fails
Renamed response fields and new status codesResponse parsing and status code checks fail
New timestamp formatDate parsing with a fixed pattern fails

Status IDs change

v2 uses different IDs for the same two states.

Statev1v2
Usable0 with Activated1 with ACTIVE
Revoked1 with Revoked3 with DELETED

A token is never in any other status. GET /api/v2/application_token/status returns both statuses.

Update any code that reads status.id. In v1, a status.id of 1 means the token is revoked. In v2, it means the token is active.

v1:

"status": { "id": 0, "description": "Activated" }

v2:

"status": { "id": 1, "description": "ACTIVE" }

Revoke tokens with a delete request

In v1, you revoke a token by setting its status in a PATCH request. In v2, PATCH no longer accepts a status. Send a DELETE request instead.

v1:

PATCH /api/v1/application_token/1234
Content-Type: application/json
{
"status": { "id": 1 }
}

v2:

DELETE /api/v2/application_token/1234

A successful delete returns 204 No Content. The application token can no longer be used to authenticate. An auth_token already generated from it stays valid until it expires, up to 240 minutes later.

v2 ignores a status field in a PATCH body instead of rejecting it. A body that contains only status fails with 400 Bad Request. A body that also contains a name renames the token and leaves it active.

Set an expiry date on every new token

In v1, expiry_date is optional, and a token without one never expires. In v2, expiry_date is required. It must be at least one day and at most 10 years in the future.

Send an ISO 8601 date, such as 2027-10-01T00:00:00Z or 2027-10-01 00:00:00. A value without a time zone is read as UTC.

If you create tokens without an expiry date today, decide how long each token should live, and plan to create a replacement before it expires. For a rotation procedure, see Handle token expiration.

v1, a token that never expires:

POST /api/v1/application_token
Content-Type: application/json
{
"description": "Customer 4711 integration"
}

v2, a token that expires after one year:

POST /api/v2/application_token
Content-Type: application/json
{
"name": "Customer 4711 integration",
"roles": [{ "id": 1 }],
"expiry_date": "2027-10-01T00:00:00Z"
}

A missing, past, or out-of-range expiry date returns 400 Bad Request:

{
"status_code": 400,
"message": "expiry_date must be no more than 10 years in the future"
}

After you create a token, you can’t change its expiry date.

Assign a role to every new token

v1 tokens always have Administrator permissions. In v2, you choose the role on creation, and roles is required. Pass exactly one role in the roles array.

RoleID
Administrator1
User2
Observer3

Custom roles from your Workspace work too. The Support role can’t be assigned to a token.

To keep the permissions your v1 tokens have, assign the Administrator role:

"roles": [{ "id": 1 }]

For least privilege, assign the role with the fewest permissions your integration needs. To change the role of an existing token, send roles in a PATCH request.

Token names are validated

In v1, the token label is called description and accepts any character. v1 accepts up to 256 characters but keeps only the first 64. In v2, it’s called name, and it must be 2 to 64 characters long after surrounding spaces are removed. Only these characters are allowed:

  • ASCII letters (a to z and A to Z) and digits
  • Spaces
  • - _ . : / ( ) [ ] @ + #

Accented and non-Latin letters, such as é or ü, aren’t allowed. A name that doesn’t match returns 400 Bad Request. If you generate token names, check your naming pattern against these rules before you switch.

v1:

{ "description": "Integration for customer ACME Corporation, EU region, production environment, created by provisioning service" }

v2:

{ "name": "ACME Corp EU prod (provisioning)" }

IP restrictions are an array

In v1, a token accepts one IP restriction, sent and returned as the string ip. In v2, you send ip_restrictions as an array of up to 100 IPv4 addresses or CIDR ranges. An address without a mask is stored as /32.

v2 ignores an ip field instead of rejecting it. A create request that still sends ip succeeds, and the new token has no IP restriction.

v1:

{ "ip": "10.203.23.78/32" }

v2 request:

{ "ip_restrictions": ["10.203.23.78", "10.10.1.0/24"] }

v2 response:

"ip_restrictions": [
{ "id": 42, "ip_address": "10.203.23.78/32" },
{ "id": 43, "ip_address": "10.10.1.0/24" }
]

A token without IP restrictions has no ip_restrictions field in the response. You can’t change the IP restrictions of an existing token.

Lists return active tokens only

GET /api/v1/application_token returns every token, including revoked ones. GET /api/v2/application_token returns active tokens only.

To include deleted tokens, filter by status with the q query parameter. Separate several statuses with ||, and percent-encode the pipes as %7C%7C.

To listRequest
Active tokensGET /api/v2/application_token
Deleted tokensGET /api/v2/application_token?q=status:3
Active and deletedGET /api/v2/application_token?q=status:1%7C%7C3

GET /api/v2/application_token/{id} returns 404 Not Found for a deleted token.

Limit of 300 active tokens per Workspace

By default, a Workspace can hold up to 300 active tokens. Deleted tokens don’t count toward the limit. The v2 create endpoint enforces the limit, and counts every active token in the Workspace, including tokens created with v1. Creating a token beyond the limit returns 422 Unprocessable Entity:

{
"status_code": 422,
"message": "Cannot create application token: the organisation already has 300 active tokens."
}

If your integration needs more active tokens in one Workspace, contact your Telia account manager before you migrate.

Response and error changes

Renamed fields

v1v2
descriptionname
createdcreated_date
ip (string)ip_restrictions (array of objects)
creator (id, name, username)created_by (id, name, username, type)

v2 also returns roles, last_used_date, last_used_ip, last_modified_date, last_modified_by, deleted_date, and deleted_by. Fields without a value are left out of the response, except name, which is null for a token created through v1 without a description.

Timestamps, including expiry_date, change format from 2027-10-01T00:00:00+0000 to 2027-10-01T00:00:00.000Z. If you parse dates with a fixed pattern, update it.

Create response

v1 returns 200 OK with the token only:

{
"application_token": "eyJhbGciOiJIUzUxMiJ9..."
}

v2 returns 201 Created with the full token details, and the secret in token:

{
"id": 1234,
"name": "Customer 4711 integration",
"status": { "id": 1, "description": "ACTIVE" },
"roles": [{ "id": 1, "name": "Administrator" }],
"expiry_date": "2027-10-01T00:00:00.000Z",
"created_date": "2026-10-01T09:00:00.000Z",
"created_by": {
"id": 10,
"username": "jane.doe@example.com",
"name": "Jane Doe",
"type": { "id": 0, "description": "HUMAN" }
},
"token": "eyJhbGciOiJIUzUxMiJ9..."
}

Read the token from token instead of application_token. As in v1, this is the only response that contains it, so store it immediately.

Update response

v1 returns 204 No Content. v2 returns 200 OK with the updated token details. A PATCH body must contain name, roles, or both.

Errors

v1 validation errors return 422 Unprocessable Entity with error_code, error_token, and errors. v2 validation errors return 400 Bad Request with status_code and message:

{
"status_code": 400,
"message": "name may contain letters, digits, spaces and - _ . : / ( ) [ ] @ + # only, name must be longer than or equal to 2 characters"
}

When a request fails several checks, message lists every failed check, separated by commas.

If your code branches on error_code or error_token, branch on the HTTP status code instead.

Migration checklist

  • Replace v1 URLs with the v2 endpoints from the endpoint mapping.
  • Map status IDs: 0 to 1, and 1 to 3.
  • Revoke tokens with DELETE instead of PATCH.
  • Send name, roles, and expiry_date on every create request.
  • Check generated token names against the new rules.
  • Send and read IP restrictions as arrays.
  • Add q=status:1%7C%7C3 where your code expects revoked tokens in the list next to active ones.
  • Read the new token from token in a 201 Created response.
  • Update response parsing for the renamed fields, timestamp format, and error format.
  • Plan token rotation for the expiry dates you choose.