Working with the Telgea Open API
Get started with the Telgea API in under 5 minutes.
Telgea Open API
The Telgea Open API follows conventional REST API standards, aligned around various resources that can be managed through the API.
Prerequisites
To work with the Open API, ensure you have:
- A Telgea organization account
- An API key: see Authentication for how you get one
Make Your First Request
The quickest first call needs no code: open the playground, paste your API key, and send List users. It is a read, so it changes nothing.
Or from a terminal:
curl -X GET https://api.telgea.com/v1/users \
-H "x-api-key: $TELGEA_API_KEY"The response includes a paginated list of users in your organization.
There is no sandbox
Every call — from the playground or from your code — runs against your own live organization. Creating a user creates a real user, and provisioning creates a real line.
Authentication
All API requests require an API key passed in the x-api-key header. Each key holds a set of
permissions that decide which operations it can call, and every operation in the
API reference names the permission it needs. How you receive a key is described under
Authentication.
Include the key in every request:
curl -X GET https://api.telgea.com/v1/users \
-H "x-api-key: $TELGEA_API_KEY"Missing or invalid API keys return a 401 Unauthorized status code. Insufficient permissions return 403 Forbidden.
To check a key before writing any code, paste it into the playground and send a read such as List users. A 403 there names the permission the key is missing.
Error Handling
The Telgea Open API uses standard HTTP status codes and returns every failure as
RFC 9457 Problem Details, served as application/problem+json.
Success responses come in the form of 200 OK, 201 Created or 204 No Content.
The error index lists every problem type the API returns, each with its own page.
| Status | code | When |
|---|---|---|
400 | VALIDATION_ERROR | The request does not match the endpoint's schema. Nothing was processed. |
400 | BAD_REQUEST | The request was refused, and no more specific code describes why — for instance, the resource is not in a state that allows the action. |
400 | INVALID_REQUEST | The request combines parameters that cannot be used together, so nothing was processed. Returned by the user-plan endpoints of the Enterprise API; other endpoints return BAD_REQUEST, which new integrations should handle. |
401 | UNAUTHORIZED | The x-api-key header is missing or invalid. |
403 | FORBIDDEN | The key is valid but lacks the permission this endpoint requires. |
403 | ORGANIZATION_ACCESS_REVOKED | Your organization's access to the API has been revoked. Contact support to restore it. |
403 | COUNTRY_NOT_SUPPORTED | The request names a country that is not enabled for your organization. |
404 | NOT_FOUND | No matching resource exists in your organization. |
405 | METHOD_NOT_ALLOWED | The path does not accept this method. The Allow response header lists the ones it does. |
409 | CONFLICT | The request conflicts with an existing resource. Nothing was created or changed. |
422 | UNPROCESSABLE_ENTITY | The request was understood but cannot be processed with these values. |
429 | RATE_LIMIT_EXCEEDED | The key has used its quota for the current window. Retry-After says when it resets. |
429 | TOO_MANY_REQUESTS | Requests for this action arrive faster than it allows, such as a second SIM replacement inside its cooldown. Retry with backoff. |
500 | INTERNAL_ERROR | Retry with exponential backoff, then contact Telgea with the requestId. |
503 | SERVICE_UNAVAILABLE | A system the request depends on is temporarily unavailable. Retry with exponential backoff; if the request creates or changes something, read the resource back first. |
Error Response Format
Every error body is a flat JSON object with the content type application/problem+json. It always
carries these members:
type— a URI naming the kind of failure. It opens that error's page on this site, which says when it occurs and what to do about it.title— a short summary of the problem type. It is the same on every occurrence.status— the HTTP status of the response.detail— what went wrong on this request, in one sentence.code— a stable machine-readable code. Branch oncodeortype, never on thedetailtext.requestId— identifies the request in Telgea's logs. Quote it when you contact support.
Some errors add extension members after these, named in camelCase, such as fields on a
validation error or missingPermission on a permission error. The error schemas in the
API reference list the members each operation's errors can carry. Ignore any member you do
not recognize.
{
"type": "https://developer.telgea.com/errors/http/NOT_FOUND",
"title": "Not found",
"status": 404,
"detail": "No resource matching this request exists in your organization.",
"code": "NOT_FOUND",
"requestId": "req_123"
}Validation Errors
A VALIDATION_ERROR adds fields, listing one entry per rejected field (at most 20). Every entry
describes the same request location: query, path and body are validated in that order, and the first
that fails answers the request.
{
"type": "https://developer.telgea.com/errors/http/VALIDATION_ERROR",
"title": "Validation error",
"status": 400,
"detail": "The request does not match this endpoint's schema, so nothing was processed.",
"code": "VALIDATION_ERROR",
"requestId": "req_123",
"fields": [
{
"field": "fields.authorizationCode",
"location": "body",
"code": "REQUIRED",
"message": "This field is required."
}
]
}location is one of body, query, path, header or cookie. code is one of REQUIRED,
INVALID_TYPE, INVALID_FORMAT, INVALID_VALUE, TOO_SMALL, TOO_LARGE, UNKNOWN_FIELD or
INVALID. field is a dotted path, with [i] for array indices, and is empty when the failure is
about the request as a whole rather than one field.
Permission Errors
A 403 raised by a missing API-key permission adds missingPermission, naming the permission the
key lacks.
{
"type": "https://developer.telgea.com/errors/http/FORBIDDEN",
"title": "Forbidden",
"status": 403,
"detail": "This API key is missing the users:read permission.",
"code": "FORBIDDEN",
"requestId": "req_123",
"missingPermission": "users:read"
}Pagination
List endpoints paginate in one of two ways. Resource collections use page numbers; the usage feed uses a cursor, because records keep arriving while you read.
Page-numbered endpoints
/v1/users, /v1/numbers and /v1/port-ins/number/{numberId} take page and pageSize query
parameters and return:
{
"page": 1,
"pageSize": 50,
"itemsCount": 142,
"items": []
}itemsCountis the total across all pages; the number of pages isMath.ceil(itemsCount / pageSize)- An empty
itemsarray withitemsCount: 0means no results match your query pageis 1-indexed, and the default and maximumpageSizediffer per endpoint:
| Endpoint | Default pageSize | Maximum pageSize |
|---|---|---|
/v1/users | 10 | 50 |
/v1/teams (Enterprise API) | 50 | 50 |
/v1/numbers (Partner API) | 50 | 100 |
/v1/user-plans (Enterprise API) | 50 | 100 |
/v1/port-ins/number/{numberId} | 50 | 100 |
The usage feed
/v1/usage takes pageSize (default 50, maximum 100) and an opaque cursor, and returns:
{
"items": [],
"nextCursor": "eyJjIjoiMjAyNi0wOS0xMVQwODozMDowMC4xMjM0NTZaIiwicyI6ImRhdGEiLCJpIjoiY2RyXzEifQ",
"hasMore": true
}Omit cursor for the first page, then pass the previous response's nextCursor to fetch the next
one. Stop when hasMore is false; nextCursor is null once the feed is exhausted. The feed
takes no page parameter and reports no total.
Rate Limits
Each API key allows 1000 requests per 24 hours, shared across every endpoint. A request over the
budget returns 429 with the code RATE_LIMIT_EXCEEDED; wait for the window to reset before retrying.
When polling usage, walk the whole organization with the default page size rather than issuing one
request per subscriber.
Retries and Idempotency
Every POST, PATCH and DELETE accepts an optional Idempotency-Key header: a value unique to the
request, of 1 to 255 printable ASCII characters. A UUID is the usual choice.
curl -X POST https://api.telgea.com/v1/numbers \
-H "x-api-key: $TELGEA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"userId": "9c1f2a6e-3b7d-4e0a-8f21-5d6c7b8a9e01", "countryCode": "DK"}'If the connection drops before the response reaches you, send the request again with the same key: rather than provisioning a second line or failing with a conflict, the API returns the original response.
- A key identifies one request to one endpoint, and is remembered for 24 hours.
- Within that window the same key replays the original outcome, including a failure, which is not re-attempted. Change the key whenever you mean to send a new request, including after correcting a rejected one.
- Keys are private to your API key and organization.
- The header is ignored on
GET, and a malformed one is rejected with400before the request has any effect.
Next Steps
- Number Provisioning — Give your users new numbers
- API Reference — Explore all available endpoints