Responses
The response envelope, pagination, data types, HTTP status codes, and the error format used across the external API.
Every endpoint in the external API shapes responses, pages lists, and reports errors the same way. Read this page once, and it applies everywhere.
Success envelope
A single resource arrives wrapped in a data object:
{
"data": {
"id": "5a6b7c8d-9e0f-1a2b-3c4d-5e6f7a8b9c0d",
"title": "Order #10428",
"status": "active"
}
}Endpoints that perform an action rather than return a resource put a human-readable string in
meta.message:
{
"meta": {
"message": "Payment link archived."
}
}Pagination
List endpoints return a data array alongside links and meta. To page through results, use the
page and per_page query parameters. per_page defaults to 15.
{
"data": [
{ "id": "5a6b7c8d-9e0f-1a2b-3c4d-5e6f7a8b9c0d", "title": "Order #10428" },
{ "id": "6b7c8d9e-0f1a-2b3c-4d5e-6f7a8b9c0d1e", "title": "Order #10429" }
],
"links": {
"first": "https://api.mytpe.app/api/ext/links?page=1",
"last": "https://api.mytpe.app/api/ext/links?page=4",
"prev": null,
"next": "https://api.mytpe.app/api/ext/links?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 15,
"per_page": 15,
"last_page": 4,
"total": 58
}
}Most list endpoints also accept search, sort_by, and sort_dir, where sort_dir is asc or
desc. Results are sorted by created_at desc unless you specify otherwise. Each resource page
lists the sort_by values that endpoint accepts.
Data types
| Type | Representation |
|---|---|
| Identifiers | UUID strings, such as "5a6b7c8d-9e0f-1a2b-3c4d-5e6f7a8b9c0d". |
| Money | Decimal strings, such as "4500.00". The currency is a three-letter code, DZD. |
| Wallet amounts | Integers in centimes. 50000 means 500.00 DZD. See Wallet. |
| Timestamps | ISO 8601 in UTC, such as "2026-06-09T12:34:56.000000Z". |
| Enums | Lowercase snake_case strings. See Statuses and enums. |
| Booleans | true or false. |
Money is a decimal string on most resources but an integer count of centimes on wallet endpoints. Mixing the two sends a payment 100 times too large or too small.
HTTP status codes
| Code | Meaning |
|---|---|
200 OK | The request succeeded. |
201 Created | The API created the resource. |
204 No Content | The request succeeded and returned no body. |
401 Unauthorized | The API credentials are missing or invalid. |
403 Forbidden | The credentials are valid, but the account can't perform this action. |
404 Not Found | The resource doesn't exist, or it belongs to another account. |
422 Unprocessable Entity | Validation failed, or a business rule rejected the request. |
500 Internal Server Error | The request failed unexpectedly. |
503 Service Unavailable | A dependency, such as the payment gateway, is temporarily unavailable. |
Errors
Errors follow JSON:API. The top-level errors key holds an
array, even when only one error is present:
{
"errors": [
{
"status": "404",
"code": "NOT_FOUND",
"title": "Resource not found",
"detail": null,
"meta": []
}
]
}Each member of the array contains these fields:
| Field | Type | Description |
|---|---|---|
status | string | The HTTP status code, as a string. |
code | string | A stable, machine-readable identifier. Branch on this value. |
title | string | A human-readable summary. This text can change; don't match on it. |
detail | string | null | Extra context, when the API has any to add. |
meta | object | array | Field-level validation messages, or an empty array. |
errors is an array, not an object, and a failed request has no top-level message key. Reading
response.error or response.message yields undefined for every error the API returns.
Common error codes
| HTTP | code | When it occurs |
|---|---|---|
401 | MISSING_API_CREDENTIALS | One or both credential headers are absent. |
401 | INVALID_API_CREDENTIALS | Both headers are present, but the key or secret doesn't match. |
403 | NON_TRADER_API_USE | The credentials belong to an account that isn't a trader. |
403 | PLAN_EXTERNAL_API_REQUIRED | The trader's plan doesn't include external API access. |
403 | WORKSPACE_ACCESS_DENIED | The X-Workspace-Id value names a workspace the account can't reach. |
404 | NOT_FOUND | The resource doesn't exist, or it belongs to another account. |
422 | VALIDATION_ERROR | One or more fields failed validation. |
422 | PLAN_LIMIT_REACHED | Creating this resource would exceed the plan's limit. |
503 | SERVICE_UNAVAILABLE | A dependency is temporarily unavailable. |
Validation errors
A validation failure returns 422 with the code VALIDATION_ERROR. Field-level messages live in
meta, keyed by field name, with an array of messages for each field:
{
"errors": [
{
"status": "422",
"code": "VALIDATION_ERROR",
"title": "Validation failed",
"detail": null,
"meta": {
"amount": ["The amount field is required when amount mode is fixed."],
"payment_instance_id": ["The selected payment instance id is invalid."]
}
}
]
}Nested fields use dot notation in the key, such as "udf1.value".
Handle errors
Branch on the HTTP status first, then on errors[0].code. Never match on title, because that text
is localized and subject to change.
const res = await fetch(url, { headers });
if (!res.ok) {
const { errors } = await res.json();
const [error] = errors;
switch (error.code) {
case "INVALID_API_CREDENTIALS":
throw new Error("Check MYTPE_API_KEY and MYTPE_API_SECRET.");
case "VALIDATION_ERROR":
// error.meta maps each field to its messages.
throw new Error(Object.entries(error.meta).map(([f, m]) => `${f}: ${m[0]}`).join("; "));
default:
throw new Error(`${error.code}: ${error.title}`);
}
}