Error format
A failed request returns an HTTP status and a body in the
RFC 9457 application/problem+json format:
{
"type": "/problems/insufficient-scope",
"title": "The API key does not hold the required scope.",
"status": 403,
"code": "insufficient_scope",
"detail": "This route requires activity:write.",
"required_scopes": ["activity:write"]
}
| Field | Meaning |
|---|---|
type | A path that names the problem. It is the code with dashes. |
title | A short summary for people |
status | The HTTP status, repeated |
code | A stable, machine-readable code. Write your error handling against this field. |
detail | What went wrong in this request. The text can change. Do not parse it. |
required_scopes | Only on insufficient_scope: the scopes that the request needs |
One exception. When no key is sent, or the value does not start with tc_live_ or
tc_test_, the reply is 401 with this body. It is not a problem body:
{ "status": 401, "message": "Unauthorized: no bearer token was sent." }
Error codes
| HTTP | code | Cause | What to do |
|---|---|---|---|
| 400 | validation_failed | The body or a parameter is not valid | Read detail and fix the request. Do not retry it unchanged. |
| 401 | (none) | No key was sent, or the value does not start with tc_live_ or tc_test_ | Send the full key in X-API-Key |
| 401 | api_key_invalid | The key is not known | Check the key |
| 401 | api_key_revoked | The key was revoked | Get a new key |
| 401 | api_key_expired | The key passed its expiry date | Get a new key |
| 403 | insufficient_scope | The key does not have a scope that the request needs | Ask for the scope in required_scopes |
| 403 | forbidden | The key cannot act on this company or record, or a write key has no source system | Check companyCode, the key's company and the key's source system |
| 403 | not_owner | The equipment belongs to another source system | Do not write records that another system owns |
| 404 | not_found | No record has this id, or it is outside the key's companies | Check the id |
| 409 | conflict | The code is taken, the record belongs to another source system, or the record changed after you read it | Read detail. For a stale update, read the record again and retry. |
| 409 | code_taken | Another piece of equipment already uses this code. This code is for equipment only. A Job code clash is conflict. | Use another code, or update the existing record |
| 429 | rate_limited | Too many requests. Reserved: the API does not enforce rate limits yet. | Wait, then retry with back-off |
| 500 | internal_error | An error on our side. A create can be saved even when it returns 500. | Before you retry a create, look the record up by its code. Retry reads later. If it continues, contact support. |
| 503 | service_unavailable | The service cannot check the key at the moment | Retry after a few seconds |
| 503 | instance_mismatch | The service is being moved or set up | Retry later. If it continues, contact support. |
Retries
| Status | Retry? | How |
|---|---|---|
429, 503 | Yes | Use exponential back-off, for example 1 s, 2 s, 4 s. Stop after 5 tries. |
500 on a read | Yes | Retry later. If it continues, contact support. |
500 on a create | Only after a check | The record can exist. Look it up by its code first, for example GET /activities?q=<code> or GET /equipment-catalog?q=<code>. A create sent again for a saved record gets 409. |
400, 401, 403, 404, 409 | No | They fail again. Fix the request first. A stale 409 is the one case where you read the record again, apply your change and send a new request. |
A PATCH that sends values the record already has changes nothing. It is safe to retry.
Contact support
Email support@matrixtimecard.com. Include the code and detail from the response,
the request method and path, and the time of the request (UTC).