# User plans

A user plan is one person's line: its number and eSIM. Provision it, look it up, replace a lost SIM and end it.

> Enterprise API · https://developer.telgea.com/docs/enterprise/api/user-plans

## The user plan object {#object}

Provision SIM cards, phone numbers, and data plans for users.

| Field | Type | Description |
| --- | --- | --- |
| `userId` | string (required) | UUID of the user who holds the plan. Example: `"9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01"` |
| `email` | string (email) (required) | Email address of the user. Example: `"anna.holm@acme.example"` |
| `firstName` | string (required) | First name of the user. Example: `"Anna"` |
| `lastName` | string (required) | Last name of the user. Example: `"Holm"` |
| `status` | enum (required) | Current status of the user plan One of: `INACTIVE`, `PROVISIONING`, `PORTING`, `PORTING_FAILED`, `ACTIVE`, `TERMINATING`, `TERMINATING_WITH_DELETION`. Example: `"ACTIVE"` |
| `teamId` | string (required) | UUID of the user's team, or null. Teams are an enterprise concept and stay null for partners. Example: `"2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70"` |
| `localNumber` | UserPlanNumber (required) | The local line: the number, where it is in provisioning, and its eSIM. |
| `localNumber.id` | string (required) | UUID of the number. This is what SIM replacement and suspension act on. Example: `"8238c1b9-c2c0-4455-9b03-4bd787052709"` |
| `localNumber.type` | enum (required) | Which line this is. One of: `local`, `travel`. Example: `"local"` |
| `localNumber.countryCode` | string (required) | Market the number belongs to, ISO 3166-1 alpha-2. Example: `"DK"` |
| `localNumber.phoneNumber` | string (required) | The number in E.164 format, or null until it has been provisioned. Example: `"+4520123456"` |
| `localNumber.state` | enum (required) | Current state of the phone number in the provisioning lifecycle One of: `PENDING`, `PORTING`, `PORTING_FAILED`, `PROVISIONING`, `READY`, `REPLACING`, `CHANGING`, `SUSPENDING`, `SUSPENDED`, `RESTORING`, `RECONFIGURING`, `DEACTIVATING`, `DEACTIVATED`, `PORTING_DISCARDED`, `PORTING_OUT`, `PORTED_OUT`. Example: `"READY"` |
| `localNumber.sim` | UserPlanSimDetails (required) | SIM details, included only when the number state is READY |
| `localNumber.sim.iccid` | string (required) | ICCID of the eSIM profile. Example: `"8945000000000000001"` |
| `localNumber.sim.activationCode` | string (required) | GSMA activation string for the eSIM. Render it as a QR code, or build an install link from it. Null until the profile has been issued. Example: `"LPA:1$SMDP.TELGEA.COM$34682-73063-9140"` |
| `localNumber.sim.pinOne` | string (required) | PIN1 of the SIM, or null. Example: `"1234"` |
| `localNumber.sim.pinTwo` | string (required) | PIN2 of the SIM, or null. Example: `"5678"` |
| `localNumber.sim.pukOne` | string (required) | PUK1, needed after three wrong PIN1 entries, or null. Example: `"12345678"` |
| `localNumber.sim.pukTwo` | string (required) | PUK2, needed after three wrong PIN2 entries, or null. Example: `"87654321"` |
| `travelNumber` | UserPlanTravelNumber (required) | The travel line and its eSIM, when the organization has one. Null for a local-only plan. |
| `travelNumber.id` | string (required) | UUID of the travel number. Example: `"81ec0bc5-b200-436d-bb70-d563ca2348d4"` |
| `travelNumber.type` | enum (required) | Which line this is. One of: `local`, `travel`. Example: `"travel"` |
| `travelNumber.phoneNumber` | string (required) | The travel number in E.164 format, or null when the profile carries data only. Example: `"+4520123456"` |
| `travelNumber.state` | enum (required) | Current state of the phone number in the provisioning lifecycle One of: `PENDING`, `PORTING`, `PORTING_FAILED`, `PROVISIONING`, `READY`, `REPLACING`, `CHANGING`, `SUSPENDING`, `SUSPENDED`, `RESTORING`, `RECONFIGURING`, `DEACTIVATING`, `DEACTIVATED`, `PORTING_DISCARDED`, `PORTING_OUT`, `PORTED_OUT`. Example: `"READY"` |
| `travelNumber.sim` | UserPlanSimDetails (required) | SIM details, included only when the number state is READY |
| `travelNumber.sim.iccid` | string (required) | ICCID of the eSIM profile. Example: `"8945000000000000001"` |
| `travelNumber.sim.activationCode` | string (required) | GSMA activation string for the eSIM. Render it as a QR code, or build an install link from it. Null until the profile has been issued. Example: `"LPA:1$SMDP.TELGEA.COM$34682-73063-9140"` |
| `travelNumber.sim.pinOne` | string (required) | PIN1 of the SIM, or null. Example: `"1234"` |
| `travelNumber.sim.pinTwo` | string (required) | PIN2 of the SIM, or null. Example: `"5678"` |
| `travelNumber.sim.pukOne` | string (required) | PUK1, needed after three wrong PIN1 entries, or null. Example: `"12345678"` |
| `travelNumber.sim.pukTwo` | string (required) | PUK2, needed after three wrong PIN2 entries, or null. Example: `"87654321"` |
| `terminationScheduledAt` | string (required) | The date this plan is scheduled to end, or null when no termination is scheduled. Set by POST /v1/user-plans/{userId}/termination. Example: `"2026-10-01T00:00:00.000Z"` |

## Operations

- `GET` [List all user plans](#list-all-user-plans)
- `POST` [Create a new user plan](#create-a-new-user-plan)
- `GET` [Search for a user plan](#search-for-a-user-plan)
- `GET` [Get user plan details](#get-user-plan-details)
- `POST` [Replace a SIM card](#replace-a-sim-card)
- `POST` [Stop a customer's mobile data](#stop-a-customer-s-mobile-data)
- `DELETE` [Restore a customer's mobile data](#restore-a-customer-s-mobile-data)
- `POST` [Suspend a customer's number](#suspend-a-customer-s-number)
- `DELETE` [Restore a customer's number](#restore-a-customer-s-number)
- `POST` [End a customer's plan](#end-a-customer-s-plan)

### List all user plans {#list-all-user-plans}

`GET /v1/user-plans` · Enterprise API

Retrieves a paginated list of user plans in your organization. A user plan represents the association between a user and their telecommunications resources (SIM cards, phone numbers, data plans).

Use filters to narrow results by user, team, or plan status. Supports pagination for large datasets.

Requires the permission `user-plans:read` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/GET/v1/user-plans). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `page` | query | integer | Page to return, starting at 1. Example: `1` |
| `pageSize` | query | integer | Items per page, at most 100. Defaults to 50. Example: `50` |
| `orderBy` | query | enum | Field to sort by. Defaults to the order the plans were created in. Example: `firstName` |
| `orderDirection` | query | enum | Sort direction. Only meaningful together with orderBy. Example: `asc` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | Successfully retrieved user plans. Returns a paginated list with total count and plan details. | `ListUserPlansResponse` |
| `400` | Request failed schema validation, or was refused by a business rule | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions to list user plans | `ForbiddenError` |
| `429` | The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (200, ListUserPlansResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `page` | integer (required) | The page these items came from. Example: `1` |
| `pageSize` | integer (required) | Items per page, as requested. Example: `50` |
| `itemsCount` | integer (required) | Total items across all pages. Divide by pageSize to get the number of pages. Example: `142` |
| `items` | array of UserPlanItem (required) | User plans on this page. |
| `items.id` | string (required) | UUID of the user plan. Example: `"f7a8b9c0-d1e2-3456-f789-012345678901"` |
| `items.userId` | string (required) | UUID of the user who holds the plan. Example: `"9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01"` |
| `items.firstName` | string (required) | First name of the user. Example: `"Anna"` |
| `items.lastName` | string (required) | Last name of the user. Example: `"Holm"` |
| `items.email` | string (email) (required) | Email address of the user. Example: `"anna.holm@acme.example"` |
| `items.status` | enum (required) | Current status of the user plan One of: `INACTIVE`, `PROVISIONING`, `PORTING`, `PORTING_FAILED`, `ACTIVE`, `TERMINATING`, `TERMINATING_WITH_DELETION`. Example: `"ACTIVE"` |
| `items.localPhoneNumber` | string (required) | The local number in E.164 format, or null until it has been provisioned. Example: `"+4520123456"` |
| `items.teamId` | string (required) | UUID of the user's team, or null. Teams are an enterprise concept and stay null for partners. Example: `"2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70"` |
| `items.teamName` | string (required) | Name of the user's team, or null. Teams are an enterprise concept and stay null for partners. Example: `"Field Sales"` |

**Example request**

```bash
curl -X GET "https://api.telgea.com/v1/user-plans" \
  -H "x-api-key: $TELGEA_API_KEY"
```

**Response 200**

```json
{
  "page": 1,
  "pageSize": 50,
  "itemsCount": 2,
  "items": [
    {
      "id": "f7a8b9c0-d1e2-3456-f789-012345678901",
      "userId": "9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01",
      "firstName": "Anna",
      "lastName": "Holm",
      "email": "anna.holm@acme.example",
      "status": "ACTIVE",
      "localPhoneNumber": "+4520123456",
      "teamId": "2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70",
      "teamName": "Field Sales"
    },
    {
      "id": "5a1c8e37-2d64-4b90-8fa2-6c0e9d4b7132",
      "userId": "3e5d1b42-7c90-4a18-b6f3-0d9e2a4c7f85",
      "firstName": "Jonas",
      "lastName": "Berg",
      "email": "jonas.berg@acme.example",
      "status": "PROVISIONING",
      "localPhoneNumber": null,
      "teamId": null,
      "teamName": null
    }
  ]
}
```

### Create a new user plan {#create-a-new-user-plan}

`POST /v1/user-plans` · Enterprise API

Provisions a local line for an existing user: a market-bound phone number and the eSIM that carries it.

The user must exist in your organization before creating a plan. Use the users endpoint to create users first if needed.

**Provisioning flow:**
1. The user plan is created and returns `PROVISIONING` — a local number id, and `travelNumberId: null`
2. A SIM is assigned from available inventory and the number allocated with the local market's operator
3. The plan reaches `ACTIVE`, and GET /v1/user-plans/{userId} carries the local number's `sim.activationCode`

A travel eSIM is **not** part of this call. One is added afterwards, on its own, and only for an organization whose contract includes one and which holds a data pool outside its home zone — poll GET /v1/user-plans/{userId} to see whether a `travelNumber` appeared.

To install the eSIM yourself, take `sim.activationCode` — a GSMA `LPA:1$…` string — from GET /v1/user-plans/{userId} and encode it as a QR code; any QR library will do.

Organizations with Telgea's end-user communications enabled also send the user installation instructions by email. White-label integrations have them switched off, so that activation code is the only delivery and presenting it is yours to do.

Requires the permission `user-plans:create` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/POST/v1/user-plans). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `idempotency-key` | header | string | A value unique to this request, of 1 to 255 printable ASCII characters — a UUID is the usual choice. Retry with the same key within 24 hours and you get the original response back, even if it was a failure, and nothing is done twice. Send a new key whenever you change the request. Keys are private to your API key and organisation. Example: `0b7e4f1c-6a2d-4c9e-8f35-d1a7b2c93e60` |

**Request body**

| Field | Type | Description |
| --- | --- | --- |
| `userId` | string (uuid) (required) | UUID of an existing user to provision a plan for Example: `"9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01"` |
| `countryCode` | string (required) | Two-character ISO country code for the user plan. Must be a valid ISO 3166-1 alpha-2 code (e.g., "DK", "US", "GB") and available in your organization's list of supported markets. Case-insensitive. Invalid codes are rejected immediately. Contact support to enable additional countries. Example: `"DK"` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | User plan created successfully. Returns the complete plan details including assigned phone numbers and SIM information. | `CreateUserPlanResponse` |
| `400` | Request failed schema validation, or the country code is not a supported ISO 3166-1 alpha-2 code | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions, or the requested country is not available for your organization: nothing it can buy covers the country, or the country requires business verification your organization has not passed. | `ForbiddenError` |
| `404` | User not found in your organization, or no local plan is available for the requested market. | `NotFoundError` |
| `409` | The user already has an active plan, so nothing was created. | `ConflictError` |
| `429` | The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (200, CreateUserPlanResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `status` | enum (required) | Current status of the user plan One of: `INACTIVE`, `PROVISIONING`, `PORTING`, `PORTING_FAILED`, `ACTIVE`, `TERMINATING`, `TERMINATING_WITH_DELETION`. Example: `"PROVISIONING"` |
| `localNumberId` | string (required) | UUID of the provisioned local number Example: `"8238c1b9-c2c0-4455-9b03-4bd787052709"` |
| `travelNumberId` | string (required) | Always `null`. This call provisions the local line alone. A travel eSIM is added afterwards, and only for an organization whose contract includes one and which holds a data pool outside its home zone. Read `travelNumber` from GET /v1/user-plans/{userId} to see whether one exists. Example: `null` |

**Example request**

```bash
curl -X POST "https://api.telgea.com/v1/user-plans" \
  -H "x-api-key: $TELGEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "userId": "9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01",
  "countryCode": "DK"
}'
```

**Response 200**

```json
{
  "status": "PROVISIONING",
  "localNumberId": "8238c1b9-c2c0-4455-9b03-4bd787052709",
  "travelNumberId": null
}
```

### Search for a user plan {#search-for-a-user-plan}

`GET /v1/user-plans/search` · Enterprise API

Search for a user plan by email address, phone number (MSISDN), or ICCID (SIM card identifier). This endpoint is useful for looking up user plans when you only have contact identifiers.

Exactly one search parameter (email, msisdn, or iccid) must be provided.

The phone number must be in E.164 format (e.g., +4520123456).

Requires the permission `user-plans:read` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/GET/v1/user-plans/search). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `email` | query | string (email) | Email address of the user to search for Example: `user@example.com` |
| `msisdn` | query | string | Phone number in E.164 format to search for Example: `+4520123456` |
| `iccid` | query | string | ICCID (SIM card identifier) to search for Example: `8944500102198304826` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | Successfully found the user plan. Returns the same detailed information as the get user plan details endpoint. | `UserPlanDetails` |
| `400` | Exactly one of email, msisdn or iccid must be provided, and it must be well formed. Sending none, or more than one, is refused here. | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions to search user plans | `ForbiddenError` |
| `404` | No user plan found matching the provided search criteria | `NotFoundError` |
| `429` | The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (200, UserPlanDetails)**

| Field | Type | Description |
| --- | --- | --- |
| `userId` | string (required) | UUID of the user who holds the plan. Example: `"9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01"` |
| `email` | string (email) (required) | Email address of the user. Example: `"anna.holm@acme.example"` |
| `firstName` | string (required) | First name of the user. Example: `"Anna"` |
| `lastName` | string (required) | Last name of the user. Example: `"Holm"` |
| `status` | enum (required) | Current status of the user plan One of: `INACTIVE`, `PROVISIONING`, `PORTING`, `PORTING_FAILED`, `ACTIVE`, `TERMINATING`, `TERMINATING_WITH_DELETION`. Example: `"ACTIVE"` |
| `teamId` | string (required) | UUID of the user's team, or null. Teams are an enterprise concept and stay null for partners. Example: `"2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70"` |
| `localNumber` | UserPlanNumber (required) | The local line: the number, where it is in provisioning, and its eSIM. |
| `localNumber.id` | string (required) | UUID of the number. This is what SIM replacement and suspension act on. Example: `"8238c1b9-c2c0-4455-9b03-4bd787052709"` |
| `localNumber.type` | enum (required) | Which line this is. One of: `local`, `travel`. Example: `"local"` |
| `localNumber.countryCode` | string (required) | Market the number belongs to, ISO 3166-1 alpha-2. Example: `"DK"` |
| `localNumber.phoneNumber` | string (required) | The number in E.164 format, or null until it has been provisioned. Example: `"+4520123456"` |
| `localNumber.state` | enum (required) | Current state of the phone number in the provisioning lifecycle One of: `PENDING`, `PORTING`, `PORTING_FAILED`, `PROVISIONING`, `READY`, `REPLACING`, `CHANGING`, `SUSPENDING`, `SUSPENDED`, `RESTORING`, `RECONFIGURING`, `DEACTIVATING`, `DEACTIVATED`, `PORTING_DISCARDED`, `PORTING_OUT`, `PORTED_OUT`. Example: `"READY"` |
| `localNumber.sim` | UserPlanSimDetails (required) | SIM details, included only when the number state is READY |
| `localNumber.sim.iccid` | string (required) | ICCID of the eSIM profile. Example: `"8945000000000000001"` |
| `localNumber.sim.activationCode` | string (required) | GSMA activation string for the eSIM. Render it as a QR code, or build an install link from it. Null until the profile has been issued. Example: `"LPA:1$SMDP.TELGEA.COM$34682-73063-9140"` |
| `localNumber.sim.pinOne` | string (required) | PIN1 of the SIM, or null. Example: `"1234"` |
| `localNumber.sim.pinTwo` | string (required) | PIN2 of the SIM, or null. Example: `"5678"` |
| `localNumber.sim.pukOne` | string (required) | PUK1, needed after three wrong PIN1 entries, or null. Example: `"12345678"` |
| `localNumber.sim.pukTwo` | string (required) | PUK2, needed after three wrong PIN2 entries, or null. Example: `"87654321"` |
| `travelNumber` | UserPlanTravelNumber (required) | The travel line and its eSIM, when the organization has one. Null for a local-only plan. |
| `travelNumber.id` | string (required) | UUID of the travel number. Example: `"81ec0bc5-b200-436d-bb70-d563ca2348d4"` |
| `travelNumber.type` | enum (required) | Which line this is. One of: `local`, `travel`. Example: `"travel"` |
| `travelNumber.phoneNumber` | string (required) | The travel number in E.164 format, or null when the profile carries data only. Example: `"+4520123456"` |
| `travelNumber.state` | enum (required) | Current state of the phone number in the provisioning lifecycle One of: `PENDING`, `PORTING`, `PORTING_FAILED`, `PROVISIONING`, `READY`, `REPLACING`, `CHANGING`, `SUSPENDING`, `SUSPENDED`, `RESTORING`, `RECONFIGURING`, `DEACTIVATING`, `DEACTIVATED`, `PORTING_DISCARDED`, `PORTING_OUT`, `PORTED_OUT`. Example: `"READY"` |
| `travelNumber.sim` | UserPlanSimDetails (required) | SIM details, included only when the number state is READY |
| `travelNumber.sim.iccid` | string (required) | ICCID of the eSIM profile. Example: `"8945000000000000001"` |
| `travelNumber.sim.activationCode` | string (required) | GSMA activation string for the eSIM. Render it as a QR code, or build an install link from it. Null until the profile has been issued. Example: `"LPA:1$SMDP.TELGEA.COM$34682-73063-9140"` |
| `travelNumber.sim.pinOne` | string (required) | PIN1 of the SIM, or null. Example: `"1234"` |
| `travelNumber.sim.pinTwo` | string (required) | PIN2 of the SIM, or null. Example: `"5678"` |
| `travelNumber.sim.pukOne` | string (required) | PUK1, needed after three wrong PIN1 entries, or null. Example: `"12345678"` |
| `travelNumber.sim.pukTwo` | string (required) | PUK2, needed after three wrong PIN2 entries, or null. Example: `"87654321"` |
| `terminationScheduledAt` | string (required) | The date this plan is scheduled to end, or null when no termination is scheduled. Set by POST /v1/user-plans/{userId}/termination. Example: `"2026-10-01T00:00:00.000Z"` |

**Example request**

```bash
curl -X GET "https://api.telgea.com/v1/user-plans/search" \
  -H "x-api-key: $TELGEA_API_KEY"
```

**Response 200**

```json
{
  "userId": "9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01",
  "email": "anna.holm@acme.example",
  "firstName": "Anna",
  "lastName": "Holm",
  "status": "ACTIVE",
  "teamId": "2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70",
  "terminationScheduledAt": null,
  "localNumber": {
    "id": "8238c1b9-c2c0-4455-9b03-4bd787052709",
    "type": "local",
    "countryCode": "DK",
    "phoneNumber": "+4520123456",
    "state": "READY",
    "sim": {
      "iccid": "8945000000000000001",
      "activationCode": "LPA:1$SMDP.TELGEA.COM$34682-73063-9140",
      "pinOne": "1234",
      "pinTwo": "5678",
      "pukOne": "12345678",
      "pukTwo": "87654321"
    }
  },
  "travelNumber": null
}
```

### Get user plan details {#get-user-plan-details}

`GET /v1/user-plans/{userId}` · Enterprise API

Retrieves detailed information about a specific user's telecommunications plan, including assigned phone numbers, SIM card details, data allowances, and usage statistics.

Use this endpoint to view the complete telecommunications setup for a particular user.

Requires the permission `user-plans:read` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/GET/v1/user-plans/{userId}). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `userId` | path | string (uuid) (required) | UUID of the user whose plan this is. Example: `9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | Successfully retrieved user plan details. Includes phone numbers, SIM information, and plan configuration. | `UserPlanDetails` |
| `400` | Request failed schema validation, or was refused by a business rule | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions to view user plan details | `ForbiddenError` |
| `404` | User not found. The specified user ID does not belong to a user in your organization. | `NotFoundError` |
| `429` | The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (200, UserPlanDetails)**

| Field | Type | Description |
| --- | --- | --- |
| `userId` | string (required) | UUID of the user who holds the plan. Example: `"9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01"` |
| `email` | string (email) (required) | Email address of the user. Example: `"anna.holm@acme.example"` |
| `firstName` | string (required) | First name of the user. Example: `"Anna"` |
| `lastName` | string (required) | Last name of the user. Example: `"Holm"` |
| `status` | enum (required) | Current status of the user plan One of: `INACTIVE`, `PROVISIONING`, `PORTING`, `PORTING_FAILED`, `ACTIVE`, `TERMINATING`, `TERMINATING_WITH_DELETION`. Example: `"ACTIVE"` |
| `teamId` | string (required) | UUID of the user's team, or null. Teams are an enterprise concept and stay null for partners. Example: `"2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70"` |
| `localNumber` | UserPlanNumber (required) | The local line: the number, where it is in provisioning, and its eSIM. |
| `localNumber.id` | string (required) | UUID of the number. This is what SIM replacement and suspension act on. Example: `"8238c1b9-c2c0-4455-9b03-4bd787052709"` |
| `localNumber.type` | enum (required) | Which line this is. One of: `local`, `travel`. Example: `"local"` |
| `localNumber.countryCode` | string (required) | Market the number belongs to, ISO 3166-1 alpha-2. Example: `"DK"` |
| `localNumber.phoneNumber` | string (required) | The number in E.164 format, or null until it has been provisioned. Example: `"+4520123456"` |
| `localNumber.state` | enum (required) | Current state of the phone number in the provisioning lifecycle One of: `PENDING`, `PORTING`, `PORTING_FAILED`, `PROVISIONING`, `READY`, `REPLACING`, `CHANGING`, `SUSPENDING`, `SUSPENDED`, `RESTORING`, `RECONFIGURING`, `DEACTIVATING`, `DEACTIVATED`, `PORTING_DISCARDED`, `PORTING_OUT`, `PORTED_OUT`. Example: `"READY"` |
| `localNumber.sim` | UserPlanSimDetails (required) | SIM details, included only when the number state is READY |
| `localNumber.sim.iccid` | string (required) | ICCID of the eSIM profile. Example: `"8945000000000000001"` |
| `localNumber.sim.activationCode` | string (required) | GSMA activation string for the eSIM. Render it as a QR code, or build an install link from it. Null until the profile has been issued. Example: `"LPA:1$SMDP.TELGEA.COM$34682-73063-9140"` |
| `localNumber.sim.pinOne` | string (required) | PIN1 of the SIM, or null. Example: `"1234"` |
| `localNumber.sim.pinTwo` | string (required) | PIN2 of the SIM, or null. Example: `"5678"` |
| `localNumber.sim.pukOne` | string (required) | PUK1, needed after three wrong PIN1 entries, or null. Example: `"12345678"` |
| `localNumber.sim.pukTwo` | string (required) | PUK2, needed after three wrong PIN2 entries, or null. Example: `"87654321"` |
| `travelNumber` | UserPlanTravelNumber (required) | The travel line and its eSIM, when the organization has one. Null for a local-only plan. |
| `travelNumber.id` | string (required) | UUID of the travel number. Example: `"81ec0bc5-b200-436d-bb70-d563ca2348d4"` |
| `travelNumber.type` | enum (required) | Which line this is. One of: `local`, `travel`. Example: `"travel"` |
| `travelNumber.phoneNumber` | string (required) | The travel number in E.164 format, or null when the profile carries data only. Example: `"+4520123456"` |
| `travelNumber.state` | enum (required) | Current state of the phone number in the provisioning lifecycle One of: `PENDING`, `PORTING`, `PORTING_FAILED`, `PROVISIONING`, `READY`, `REPLACING`, `CHANGING`, `SUSPENDING`, `SUSPENDED`, `RESTORING`, `RECONFIGURING`, `DEACTIVATING`, `DEACTIVATED`, `PORTING_DISCARDED`, `PORTING_OUT`, `PORTED_OUT`. Example: `"READY"` |
| `travelNumber.sim` | UserPlanSimDetails (required) | SIM details, included only when the number state is READY |
| `travelNumber.sim.iccid` | string (required) | ICCID of the eSIM profile. Example: `"8945000000000000001"` |
| `travelNumber.sim.activationCode` | string (required) | GSMA activation string for the eSIM. Render it as a QR code, or build an install link from it. Null until the profile has been issued. Example: `"LPA:1$SMDP.TELGEA.COM$34682-73063-9140"` |
| `travelNumber.sim.pinOne` | string (required) | PIN1 of the SIM, or null. Example: `"1234"` |
| `travelNumber.sim.pinTwo` | string (required) | PIN2 of the SIM, or null. Example: `"5678"` |
| `travelNumber.sim.pukOne` | string (required) | PUK1, needed after three wrong PIN1 entries, or null. Example: `"12345678"` |
| `travelNumber.sim.pukTwo` | string (required) | PUK2, needed after three wrong PIN2 entries, or null. Example: `"87654321"` |
| `terminationScheduledAt` | string (required) | The date this plan is scheduled to end, or null when no termination is scheduled. Set by POST /v1/user-plans/{userId}/termination. Example: `"2026-10-01T00:00:00.000Z"` |

**Example request**

```bash
curl -X GET "https://api.telgea.com/v1/user-plans/9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01" \
  -H "x-api-key: $TELGEA_API_KEY"
```

**Response 200**

```json
{
  "userId": "9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01",
  "email": "anna.holm@acme.example",
  "firstName": "Anna",
  "lastName": "Holm",
  "status": "ACTIVE",
  "teamId": "2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70",
  "terminationScheduledAt": null,
  "localNumber": {
    "id": "8238c1b9-c2c0-4455-9b03-4bd787052709",
    "type": "local",
    "countryCode": "DK",
    "phoneNumber": "+4520123456",
    "state": "READY",
    "sim": {
      "iccid": "8945000000000000001",
      "activationCode": "LPA:1$SMDP.TELGEA.COM$34682-73063-9140",
      "pinOne": "1234",
      "pinTwo": "5678",
      "pukOne": "12345678",
      "pukTwo": "87654321"
    }
  },
  "travelNumber": null
}
```

### Replace a SIM card {#replace-a-sim-card}

`POST /v1/user-plans/{userId}/sim-replacement` · Enterprise API

Initiates a SIM card replacement (eSIM swap) for a specific number within a user's plan. This provisions a new eSIM and deactivates the previous one.

> **Important:** This endpoint should **only** be used when the end-user changes devices and the existing eSIM activation QR code (LPA string) has been confirmed to be expired or no longer working. Do **not** use this endpoint to troubleshoot connectivity issues — contact support instead.

**Rate limit:** one replacement per number inside the cooldown your organization's SIM-swap offering sets, counted from when the number's last replacement finished — and once per calendar day for a German number. A request inside the window gets a `429` naming when to retry.

**Flow:**
1. A new eSIM profile is provisioned and the old SIM is deactivated
2. Until the new profile is ready, GET /v1/user-plans/{userId} reports the number with `sim: null` — its state is `REPLACING`, and SIM details are published only in `READY`
3. Back in `READY`, the number's `sim.activationCode` is the new one to render as a QR code

Organizations with Telgea's end-user communications enabled also email the user the new activation code. White-label integrations have them switched off and present it themselves.

**Scopes:** `numbers:replace-sim` and `user-plans:read` — the number is checked against the addressed user's plan before any replacement is started.

Requires the permissions `numbers:replace-sim` and `user-plans:read` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/POST/v1/user-plans/{userId}/sim-replacement). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `userId` | path | string (uuid) (required) | UUID of the user whose plan this is. Example: `9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01` |
| `idempotency-key` | header | string | A value unique to this request, of 1 to 255 printable ASCII characters — a UUID is the usual choice. Retry with the same key within 24 hours and you get the original response back, even if it was a failure, and nothing is done twice. Send a new key whenever you change the request. Keys are private to your API key and organisation. Example: `0b7e4f1c-6a2d-4c9e-8f35-d1a7b2c93e60` |

**Request body**

| Field | Type | Description |
| --- | --- | --- |
| `numberId` | string (uuid) (required) | UUID of the number to replace the SIM for. Obtain from the user plan details endpoint (localNumber.id or travelNumber.id). Example: `"8238c1b9-c2c0-4455-9b03-4bd787052709"` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `202` | SIM replacement request accepted and processed asynchronously. Poll GET /v1/user-plans/{userId} until the number is READY again with its new SIM. | `ReplaceSimResponse` |
| `400` | Request failed schema validation, or was refused by a business rule | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions to replace SIM cards | `ForbiddenError` |
| `404` | User plan or number not found | `NotFoundError` |
| `429` | The number's last SIM replacement finished too recently for another: your organization's SIM-swap offering sets the cooldown (a German number is replaced once per calendar day), and `Retry-After` says when to retry. The same status also answers a key that has used its request quota. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (202, ReplaceSimResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `status` | string (required) | Status of the SIM replacement request Example: `"accepted"` |

**Example request**

```bash
curl -X POST "https://api.telgea.com/v1/user-plans/9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01/sim-replacement" \
  -H "x-api-key: $TELGEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "numberId": "8238c1b9-c2c0-4455-9b03-4bd787052709"
}'
```

**Response 202**

```json
{
  "status": "accepted"
}
```

### Stop a customer's mobile data {#stop-a-customer-s-mobile-data}

`POST /v1/user-plans/{userId}/data-restriction` · Enterprise API

Stops mobile data for one of your customers — for someone who has used up what they paid for. Calls and texts keep working; use the suspension endpoint to stop the whole line.

The call returns once the change has taken effect at the network, so a `200` means the data is genuinely off. Nothing here is queued for later.

Stopping data that is already stopped returns `409` and changes nothing. Our own automated processes never undo a stop you made — only `DELETE` on this path does.

Not every market offers stopping data on its own. Where it does not, this returns `422` and nothing changes — the Markets page in the documentation lists which is which.

Requires the permission `numbers:suspend` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/POST/v1/user-plans/{userId}/data-restriction). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `userId` | path | string (uuid) (required) | UUID of the user whose plan this is. Example: `9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01` |
| `idempotency-key` | header | string | A value unique to this request, of 1 to 255 printable ASCII characters — a UUID is the usual choice. Retry with the same key within 24 hours and you get the original response back, even if it was a failure, and nothing is done twice. Send a new key whenever you change the request. Keys are private to your API key and organisation. Example: `0b7e4f1c-6a2d-4c9e-8f35-d1a7b2c93e60` |

**Request body**

| Field | Type | Description |
| --- | --- | --- |
| `reason` | string | Free text kept with the change and shown to our support staff. Example: `"Customer exceeded their agreed data allowance."` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | Data stopped. Lists the numbers the stop reached and when it took effect. | `DataRestrictionResponse` |
| `400` | Request failed schema validation, or was refused by a business rule | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions for this action | `ForbiddenError` |
| `404` | User not found. The specified user ID does not belong to a user in your organization. | `NotFoundError` |
| `409` | Already in the state you asked for, so nothing was changed. | `ConflictError` |
| `422` | Nothing was changed: the subscriber belongs to no data pool, so there is no data to stop, or their market does not offer stopping data on its own. | `UnprocessableEntityError` |
| `429` | The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (200, DataRestrictionResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `numbers` | array of string (required) | The phone numbers the request actually reached at the network. Example: `["+4520123456"]` |
| `effectiveAt` | string (required) | When the change took effect at the network. Example: `"2026-09-14T09:30:00.000Z"` |

**Example request**

```bash
curl -X POST "https://api.telgea.com/v1/user-plans/9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01/data-restriction" \
  -H "x-api-key: $TELGEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Customer exceeded their agreed data allowance."
}'
```

**Response 200**

```json
{
  "numbers": [
    "+4520123456"
  ],
  "effectiveAt": "2026-09-14T09:30:00.000Z"
}
```

### Restore a customer's mobile data {#restore-a-customer-s-mobile-data}

`DELETE /v1/user-plans/{userId}/data-restriction` · Enterprise API

Undoes a stop made with `POST /v1/user-plans/{userId}/data-restriction`, and returns once data is live again at the network.

Restoring data that is not stopped returns `409`. Data stays off if the customer is also over an allowance you set — clear that first.

Requires the permission `numbers:unsuspend` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/DELETE/v1/user-plans/{userId}/data-restriction). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `userId` | path | string (uuid) (required) | UUID of the user whose plan this is. Example: `9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01` |
| `reason` | query | string | Free text kept with the change. Example: `Customer settled their account.` |
| `idempotency-key` | header | string | A value unique to this request, of 1 to 255 printable ASCII characters — a UUID is the usual choice. Retry with the same key within 24 hours and you get the original response back, even if it was a failure, and nothing is done twice. Send a new key whenever you change the request. Keys are private to your API key and organisation. Example: `0b7e4f1c-6a2d-4c9e-8f35-d1a7b2c93e60` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | Data restored. Lists the numbers the restore reached and when it took effect. | `DataRestrictionResponse` |
| `400` | Request failed schema validation, or was refused by a business rule | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions for this action | `ForbiddenError` |
| `404` | User not found. The specified user ID does not belong to a user in your organization. | `NotFoundError` |
| `409` | Already in the state you asked for, so nothing was changed. | `ConflictError` |
| `429` | The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (200, DataRestrictionResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `numbers` | array of string (required) | The phone numbers the request actually reached at the network. Example: `["+4520123456"]` |
| `effectiveAt` | string (required) | When the change took effect at the network. Example: `"2026-09-14T09:30:00.000Z"` |

**Example request**

```bash
curl -X DELETE "https://api.telgea.com/v1/user-plans/9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01/data-restriction" \
  -H "x-api-key: $TELGEA_API_KEY"
```

**Response 200**

```json
{
  "numbers": [
    "+4520123456"
  ],
  "effectiveAt": "2026-09-14T09:30:00.000Z"
}
```

### Suspend a customer's number {#suspend-a-customer-s-number}

`POST /v1/user-plans/{userId}/suspension` · Enterprise API

Stops all traffic on one of a customer's numbers, domestic and international — for a phone that has been lost or stolen. To stop only mobile data and leave the line usable, use the data-restriction endpoint.

The call returns once the line is down at the network, so a `200` means the service is genuinely stopped.

Suspending a number that is already suspended returns `409` and changes nothing.

Not every market offers suspension. Where it does not, this returns `400` and the line stays live — the Markets page in the documentation lists which is which.

Requires the permission `numbers:suspend` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/POST/v1/user-plans/{userId}/suspension). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `userId` | path | string (uuid) (required) | UUID of the user whose plan this is. Example: `9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01` |
| `idempotency-key` | header | string | A value unique to this request, of 1 to 255 printable ASCII characters — a UUID is the usual choice. Retry with the same key within 24 hours and you get the original response back, even if it was a failure, and nothing is done twice. Send a new key whenever you change the request. Keys are private to your API key and organisation. Example: `0b7e4f1c-6a2d-4c9e-8f35-d1a7b2c93e60` |

**Request body**

| Field | Type | Description |
| --- | --- | --- |
| `numberId` | string (uuid) (required) | UUID of the number to suspend. Obtain it from the user plan details endpoint. Example: `"8238c1b9-c2c0-4455-9b03-4bd787052709"` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | Number suspended. Lists the number the suspension reached. | `SuspensionResponse` |
| `400` | Request failed schema validation, or was refused by a business rule | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions for this action | `ForbiddenError` |
| `404` | User plan or number not found | `NotFoundError` |
| `409` | Already in the state you asked for, so nothing was changed. | `ConflictError` |
| `429` | The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (200, SuspensionResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `numbers` | array of string (required) | The phone numbers the request actually reached at the network. Example: `["+4520123456"]` |

**Example request**

```bash
curl -X POST "https://api.telgea.com/v1/user-plans/9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01/suspension" \
  -H "x-api-key: $TELGEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "numberId": "8238c1b9-c2c0-4455-9b03-4bd787052709"
}'
```

**Response 200**

```json
{
  "numbers": [
    "+4520123456"
  ]
}
```

### Restore a customer's number {#restore-a-customer-s-number}

`DELETE /v1/user-plans/{userId}/suspension` · Enterprise API

Undoes a suspension made with `POST /v1/user-plans/{userId}/suspension`, and returns once the line is live again at the network.

Restoring a number that is not suspended returns `409`.

Requires the permission `numbers:unsuspend` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/DELETE/v1/user-plans/{userId}/suspension). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `userId` | path | string (uuid) (required) | UUID of the user whose plan this is. Example: `9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01` |
| `numberId` | query | string (uuid) (required) | UUID of the number to restore. Example: `8238c1b9-c2c0-4455-9b03-4bd787052709` |
| `idempotency-key` | header | string | A value unique to this request, of 1 to 255 printable ASCII characters — a UUID is the usual choice. Retry with the same key within 24 hours and you get the original response back, even if it was a failure, and nothing is done twice. Send a new key whenever you change the request. Keys are private to your API key and organisation. Example: `0b7e4f1c-6a2d-4c9e-8f35-d1a7b2c93e60` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | Number restored. Lists the number the restore reached. | `SuspensionResponse` |
| `400` | Request failed schema validation, or was refused by a business rule | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions for this action | `ForbiddenError` |
| `404` | User plan or number not found | `NotFoundError` |
| `409` | Already in the state you asked for, so nothing was changed. | `ConflictError` |
| `429` | The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (200, SuspensionResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `numbers` | array of string (required) | The phone numbers the request actually reached at the network. Example: `["+4520123456"]` |

**Example request**

```bash
curl -X DELETE "https://api.telgea.com/v1/user-plans/9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01/suspension" \
  -H "x-api-key: $TELGEA_API_KEY"
```

**Response 200**

```json
{
  "numbers": [
    "+4520123456"
  ]
}
```

### End a customer's plan {#end-a-customer-s-plan}

`POST /v1/user-plans/{userId}/termination` · Enterprise API

Ends the customer's line on the date you name — the date they agreed to stop.

The line is suspended on that date and deactivated at the network 14 days later. The call returns as soon as the termination is scheduled, so a `202` means it is booked, not that the line is already down. Read it back on `GET /v1/user-plans/{userId}` as `terminationScheduledAt`.

**Billing is not prorated.** The customer keeps the period they already bought: the line stops on your date, and billing runs to `activeUntil` in the response. The plan does not renew afterwards.

Send `deleteUser: true` to delete the end-user along with the line. Otherwise the user remains, and `DELETE /v1/users/{userId}` succeeds once the line is suspended — you do not have to wait out the grace period.

Requires the permission `orders:cancel` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/user-plans/POST/v1/user-plans/{userId}/termination). Calls run against your live organization; there is no sandbox.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `userId` | path | string (uuid) (required) | UUID of the user whose plan this is. Example: `9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01` |
| `idempotency-key` | header | string | A value unique to this request, of 1 to 255 printable ASCII characters — a UUID is the usual choice. Retry with the same key within 24 hours and you get the original response back, even if it was a failure, and nothing is done twice. Send a new key whenever you change the request. Keys are private to your API key and organisation. Example: `0b7e4f1c-6a2d-4c9e-8f35-d1a7b2c93e60` |

**Request body**

| Field | Type | Description |
| --- | --- | --- |
| `terminationDate` | string (date) (required) | The date the customer agreed to stop, as YYYY-MM-DD. Today is allowed; a past date is rejected. Example: `"2026-10-01"` |
| `deleteUser` | boolean | Delete the end-user once their line is gone. Defaults to false, in which case the user remains and can be deleted with DELETE /v1/users/{userId} once the line is suspended. Example: `false` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `202` | Termination scheduled. States the date, when billing stops, and the lines ending. | `TerminationResponse` |
| `400` | Request failed schema validation, or was refused by a business rule | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions for this action | `ForbiddenError` |
| `404` | No plan to end exists for this user in your organization | `NotFoundError` |
| `429` | The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets. | `TooManyRequestsError` |
| `500` | Internal server error. Contact support if this persists. | `InternalError` |

**Response fields (202, TerminationResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `terminationDate` | string (required) | The date the line stops, as accepted. Example: `"2026-10-01"` |
| `activeUntil` | string (required) | The end of the period already paid for. Billing runs to this date even when the line stops earlier; null when the plan carried no billing period. Example: `"2026-12-31T00:00:00.000Z"` |
| `numberIds` | array of string (required) | The lines this termination ends, by their number ids. Example: `["9f1c6f3e-4f4a-4f2e-bb2a-2b9a1f0c8e11"]` |

**Example request**

```bash
curl -X POST "https://api.telgea.com/v1/user-plans/9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01/termination" \
  -H "x-api-key: $TELGEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "terminationDate": "2026-10-01",
  "deleteUser": true
}'
```

**Response 202**

```json
{
  "terminationDate": "2026-10-01",
  "activeUntil": "2026-12-31T00:00:00.000Z",
  "numberIds": [
    "8238c1b9-c2c0-4455-9b03-4bd787052709"
  ]
}
```
