# Users

The people in your organisation who hold a line: create them, keep their details current, and remove them when they leave.

> Enterprise API · https://developer.telgea.com/docs/enterprise/api/users

## The user object {#object}

Manage employees and contractors in your organization.

| Field | Type | Description |
| --- | --- | --- |
| `id` | string (required) | UUID of the user. Use it to provision a plan, submit a port-in, or update the user. Example: `"9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01"` |
| `email` | string (email) (required) | Email address. Unique within your organization. Example: `"anna.holm@acme.example"` |
| `firstName` | string (required) | First name. Example: `"Anna"` |
| `lastName` | string (required) | Last name. Example: `"Holm"` |
| `teamId` | string (required) | UUID of the team the user belongs to, or null. Example: `"2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70"` |
| `employeeId` | string (required) | Your own identifier for this person, as sent on create or update, or null. Example: `"EMP-0142"` |
| `costCode` | string (required) | Cost center code used on invoices, or null. Example: `"CC-4100"` |

## Operations

- `GET` [List users](#list-users)
- `POST` [Create a new user](#create-a-new-user)
- `PATCH` [Update a user](#update-a-user)
- `DELETE` [Delete a user](#delete-a-user)
- `GET` [Get a user's cost threshold and spend](#get-a-user-s-cost-threshold-and-spend)

### List users {#list-users}

`GET /v1/users` · Enterprise API + Partner API

Lists all users in your organization with pagination and optional filtering.

You can filter the results by exact email address or employee ID. Use pagination parameters to control the number of results returned per page.

Requires the permission `users:read` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/users/GET/v1/users). 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 50. Defaults to 10. Example: `10` |
| `email` | query | string (email) | Filter by exact email address Example: `anna.holm@acme.example` |
| `employeeId` | query | string | Filter by exact employee ID Example: `EMP-0142` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | Successfully retrieved list of users | `ListUsersResponse` |
| `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 users | `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, ListUsersResponse)**

| 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 UserListItem (required) | Users on this page. |
| `items.id` | string (required) | UUID of the user. Use it to provision a plan, submit a port-in, or update the user. Example: `"9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01"` |
| `items.email` | string (email) (required) | Email address. Unique within your organization. Example: `"anna.holm@acme.example"` |
| `items.firstName` | string (required) | First name. Example: `"Anna"` |
| `items.lastName` | string (required) | Last name. Example: `"Holm"` |
| `items.teamId` | string (required) | UUID of the team the user belongs to, or null. Example: `"2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70"` |
| `items.employeeId` | string (required) | Your own identifier for this person, as sent on create or update, or null. Example: `"EMP-0142"` |
| `items.costCode` | string (required) | Cost center code used on invoices, or null. Example: `"CC-4100"` |

**Example request**

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

**Response 200**

```json
{
  "page": 1,
  "pageSize": 10,
  "itemsCount": 2,
  "items": [
    {
      "id": "9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01",
      "email": "anna.holm@acme.example",
      "firstName": "Anna",
      "lastName": "Holm",
      "teamId": "2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70",
      "employeeId": "EMP-0142",
      "costCode": "CC-4100"
    },
    {
      "id": "3e5d1b42-7c90-4a18-b6f3-0d9e2a4c7f85",
      "email": "jonas.berg@acme.example",
      "firstName": "Jonas",
      "lastName": "Berg",
      "teamId": null,
      "employeeId": null,
      "costCode": null
    }
  ]
}
```

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

`POST /v1/users` · Enterprise API + Partner API

Creates a new user in your organization. Use this endpoint to onboard employees or contractors who need mobile numbers or telecommunications resources.

Once created, the user can be assigned to teams, associated with billing entities, and provisioned with SIM cards through the user-plans endpoint.

Requires the permission `users:create` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/users/POST/v1/users). 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 |
| --- | --- | --- |
| `email` | string (email) (required) | Email address of the new user. Unique within your organization. Example: `"anna.holm@acme.example"` |
| `firstName` | string (required) | First name Example: `"Anna"` |
| `lastName` | string (required) | Last name Example: `"Holm"` |
| `teamId` | string (uuid) | Team to assign the user to. Omitted, the user joins the default team, Unassigned. Example: `"2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70"` |
| `costCode` | string | Cost center code for billing purposes Example: `"CC-4100"` |
| `employeeId` | string | External employee identifier Example: `"EMP-0142"` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | User created successfully. Returns the created user object including the auto-generated user ID. | `CreateUserResponse` |
| `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 create users | `ForbiddenError` |
| `404` | `teamId` names no team in your organization | `NotFoundError` |
| `409` | No user was created: another user already holds this email address. | `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, CreateUserResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `id` | string (required) | UUID of the created user. Use it to provision a plan, submit a port-in, or update the user. Example: `"9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01"` |
| `email` | string (email) (required) | Email address as stored. Example: `"anna.holm@acme.example"` |
| `firstName` | string (required) | First name as stored. Example: `"Anna"` |
| `lastName` | string (required) | Last name as stored. Example: `"Holm"` |

**Example request**

```bash
curl -X POST "https://api.telgea.com/v1/users" \
  -H "x-api-key: $TELGEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "anna.holm@acme.example",
  "firstName": "Anna",
  "lastName": "Holm",
  "teamId": "2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70",
  "costCode": "CC-4100",
  "employeeId": "EMP-0142"
}'
```

**Response 200**

```json
{
  "id": "9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01",
  "email": "anna.holm@acme.example",
  "firstName": "Anna",
  "lastName": "Holm"
}
```

### Update a user {#update-a-user}

`PATCH /v1/users/{userId}` · Enterprise API + Partner API

Updates an existing user's information. All fields are optional - only provide the fields you want to update.

You can update basic information like name, as well as organizational assignments like team membership, cost center codes, and employee IDs.

Requires the permission `users:update` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/users/PATCH/v1/users/{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. 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 |
| --- | --- | --- |
| `email` | string (email) | Email address Example: `"anna.holm@acme.example"` |
| `firstName` | string | First name Example: `"Anna"` |
| `lastName` | string | Last name Example: `"Holm"` |
| `teamId` | string (uuid) | Team to assign the user to. null moves the user to the default team, Unassigned. Example: `"2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70"` |
| `costCode` | string | Cost center code for billing purposes (null to remove) Example: `"CC-4100"` |
| `employeeId` | string | External employee identifier (null to remove) Example: `"EMP-0142"` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `204` | User updated successfully. No content returned. | none |
| `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 update users | `ForbiddenError` |
| `404` | User not found, or `teamId` names no team in your organization | `NotFoundError` |
| `409` | No change was made: another user already holds this email address. | `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` |

**Example request**

```bash
curl -X PATCH "https://api.telgea.com/v1/users/9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01" \
  -H "x-api-key: $TELGEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "anna.holm@acme.example",
  "firstName": "Anna",
  "lastName": "Holm-Jensen",
  "teamId": "2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70",
  "costCode": "CC-4100",
  "employeeId": "EMP-0142"
}'
```

### Delete a user {#delete-a-user}

`DELETE /v1/users/{userId}` · Enterprise API + Partner API

Permanently deletes a user from your organization.

**Important Restrictions:**
- Cannot delete users with active phone numbers (must terminate user plan first)
- Cannot delete admin users
- Cannot delete yourself

Before deleting, ensure the user's local number is in SUSPENDED, DEACTIVATED state, or doesn't exist.

Requires the permission `users:delete` on the key.

[Try it in the playground](https://developer.telgea.com/playground#tag/users/DELETE/v1/users/{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. 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` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `204` | User deleted successfully. No content returned. | none |
| `400` | Cannot delete user with active phone numbers | none |
| `401` | Missing or invalid API key in the X-API-Key header | `UnauthorizedError` |
| `403` | Insufficient permissions, or attempting to delete self or admin user | `ForbiddenError` |
| `404` | User not found | `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` |

**Example request**

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

### Get a user's cost threshold and spend {#get-a-user-s-cost-threshold-and-spend}

`GET /v1/users/{userId}/cost-thresholds/{usageType}` · Enterprise API + Partner API

Where a user stands against their cost threshold on one usage type: the threshold in force for them (their own, else their team's, else the organization's), their spend this month against it, and whether the usage is paused for crossing it.

The spend is converted into the threshold's currency at the day's exchange rate, so it is approximate; usage already under way may take it past the threshold before it ends.

Thresholds are set with `PUT /v1/cost-thresholds`. A usage type with no threshold support yet answers `422`.

**Scope:** `users:read`.

Requires the permission `users:read` on the key.

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

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `userId` | path | string (uuid) (required) | UUID of the user. Example: `9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01` |
| `usageType` | path | enum (required) | The usage type the threshold is on. `VOICE` is international calling: reaching it pauses international calls and SMS on the person's lines, where their market offers the pause. Other types answer `422` until the platform can enforce them. Example: `VOICE` |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | The user's threshold, spend and pause on the usage type. | `UserCostThresholdResponse` |
| `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 users | `ForbiddenError` |
| `404` | No user in your organization has this id, so nothing was read or changed. | `NotFoundError` |
| `422` | No threshold can stand on this usage type yet, so nothing was read or changed. | `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, UserCostThresholdResponse)**

| Field | Type | Description |
| --- | --- | --- |
| `threshold` | CostThreshold or null (required) | The threshold in force for the user: their own, else their team's, else the organization's. Null when none is set. |
| `threshold.id` | string (required) | UUID of the threshold. Example: `"5d0b2c1e-7f3a-4b6c-9e8d-2a1f0c3b4d5e"` |
| `threshold.usageType` | enum (required) | The usage type the threshold is on. `VOICE` is international calling: reaching it pauses international calls and SMS on the person's lines, where their market offers the pause. Other types answer `422` until the platform can enforce them. One of: `DATA`, `VOICE`, `SMS`, `MMS`. Example: `"VOICE"` |
| `threshold.scope` | enum (required) | Whose threshold this is: the organization's default, a team's, or one user's own. One of: `organization`, `team`, `user`. Example: `"team"` |
| `threshold.teamId` | string (required) | The team, for a team threshold. Example: `"2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70"` |
| `threshold.userId` | string (required) | The user, for a user threshold. Example: `null` |
| `threshold.maxAmount` | number (required) | What one person may spend on the usage type per month, in `currency`. Example: `50` |
| `threshold.currency` | string (required) | ISO 4217 code of the threshold's money: the team's cost-center currency, else the organization's primary. Example: `"EUR"` |
| `threshold.period` | enum (required) | The period the spend is counted in. Always the calendar month. One of: `monthly`. Example: `"monthly"` |
| `threshold.validFrom` | string (required) | When the threshold opens (ISO 8601). A threshold lowered below someone's spend opens next month. Example: `"2026-10-01T00:00:00.000Z"` |
| `threshold.validTo` | string (required) | When the threshold closes (ISO 8601), or null while it stands. Example: `null` |
| `spend` | CostSpend or null (required) | Their spend this month against it. Null when no threshold is in force, or the spend could not be converted. |
| `spend.amount` | number (required) | The user's spend on the usage type this month, in `currency`. Example: `12.4` |
| `spend.currency` | string (required) | ISO 4217 code: the threshold's money. Example: `"EUR"` |
| `spend.periodStart` | string (required) | Start of the month the spend is counted in (ISO 8601). Example: `"2026-10-01T00:00:00.000Z"` |
| `pausedUntil` | string (required) | While the usage is paused on their lines for crossing the threshold: when the pause lifts (ISO 8601). Null otherwise. Example: `null` |

**Example request**

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

**Response 200**

```json
{
  "threshold": {
    "id": "5d0b2c1e-7f3a-4b6c-9e8d-2a1f0c3b4d5e",
    "usageType": "VOICE",
    "scope": "team",
    "teamId": "2f6b0d3a-8c1e-4a7f-9b2d-1e3c4d5f6a70",
    "userId": null,
    "maxAmount": 50,
    "currency": "EUR",
    "period": "monthly",
    "validFrom": "2026-10-01T00:00:00.000Z",
    "validTo": null
  },
  "spend": {
    "amount": 12.4,
    "currency": "EUR",
    "periodStart": "2026-10-01T00:00:00.000Z"
  },
  "pausedUntil": null
}
```
