Skip to content

Error Handling

The TreasuryHub API returns structured error objects on every non-2xx response. Always react to the errorCode field — the title and detail strings are human-readable and may change between releases.

Returned for authentication failures, header validation, and infrastructure errors:

{
"status": 401,
"errorCode": "ERR-1002",
"title": "Invalid authentication token."
}

Returned when the request body fails validation. The top-level errorCode is the code of the first failure; the errors array lists every failure in the request:

{
"status": 400,
"errorCode": "ERR-3001",
"title": "One or more validation errors occurred.",
"errors": [
{
"field": "ExternalId",
"errorCode": "ERR-3001",
"message": "ExternalId is required."
},
{
"field": "Amount",
"errorCode": "ERR-3005",
"message": "Amount must be greater than 0."
}
]
}
CodeHTTPWhen it occurs
ERR-1001401Authentication header absent
ERR-1002401Authentication token invalid
ERR-1003403Authenticated but not authorized for the resource
ERR-2001400Tenant header absent
ERR-2002400Tenant header is not a valid UUID
ERR-3001400externalId is empty or missing
ERR-3002400type is not INTERNAL_PAYIN or INTERNAL_PAYOUT
ERR-3003400countryCode is not a valid ISO 3166-1 alpha-2 code
ERR-3004400currencyCode is not a valid ISO 4217 code
ERR-3005400amount is zero or negative
ERR-3006400status is not PENDING, REJECTED, or BOOKED
ERR-3007400A multiCurrencyAmounts[].currencyCode is not a valid ISO 4217 code
ERR-3008400A multiCurrencyAmounts[].amount is zero or negative
ERR-3009400Payout-only field provided in a payin payload
ERR-3010400Payin-only field provided in a payout payload
ERR-3011400payload.channel is not CASH, ONLINE, or CRYPTO
ERR-4001400externalId already exists for this tenant
ERR-4002404No financial event found for the given UUID and tenant
ERR-5001500Unexpected internal error

ERR-1001 / ERR-1002 — Authentication errors

Section titled “ERR-1001 / ERR-1002 — Authentication errors”

Check that every request includes all three required headers:

X-Client-Id: {{tenant_id}}
X-Access-Token: {{access_token}}
Content-Type: application/json

ERR-1001 means a required authentication header is absent. ERR-1002 means the token value is present but invalid — verify the token matches the environment (th_live_ for Production, th_test_ for Sandbox). Tokens from one environment do not work in the other.


type must be exactly INTERNAL_PAYIN or INTERNAL_PAYOUT — uppercase, no other variants accepted.


ERR-3009 / ERR-3010 — Payload field mismatch

Section titled “ERR-3009 / ERR-3010 — Payload field mismatch”

The payload object has distinct allowed fields per event type:

  • INTERNAL_PAYIN: use payerName, payerPersonalIdType, payerPersonalId.
  • INTERNAL_PAYOUT: use beneficiaryName, beneficiaryPersonalIdType, beneficiaryPersonalId.

Sending a field that belongs to the other type causes a 400. Unknown fields are also rejected — the payload schema does not allow additionalProperties.


externalId must be unique per tenant. The API has no idempotency header — if a POST already returned 201, do not retry it with the same externalId.

If the intent is to update an existing event, use PUT /api/h2h/ingestion/financial-events/{uuid} with the UUID returned by the original POST.


Verify:

  1. The UUID in the path is the one returned in the POST response body (uuid field), not the externalId.
  2. The X-Client-Id is the same tenant that created the event — cross-tenant lookups always return 404.

Contact TreasuryHub support with the full request and the timestamp. Do not retry automatically — submit the event again only after confirming the original was not persisted.

async function callApi(url, options) {
const response = await fetch(url, options);
if (response.ok) return response.json();
const error = await response.json();
// Always branch on errorCode, not on HTTP status or title
switch (error.errorCode) {
case 'ERR-4001':
throw new Error(`Duplicate externalId — event already exists.`);
case 'ERR-1001':
case 'ERR-1002':
throw new Error(`Authentication failed — check X-Client-Id and X-Access-Token.`);
default:
if (error.errors?.length) {
// Validation failure — log each field error
for (const e of error.errors) {
console.error(`[${e.errorCode}] ${e.field}: ${e.message}`);
}
}
throw new Error(`API error ${error.errorCode}: ${error.title}`);
}
}

The Financial Events API uses externalId for deduplication — there is no Idempotency-Key header. A request that returns 201 must not be retried with the same externalId. A request that returns 5xx or times out may be retried with the same externalId only if you have confirmed the event was not created (use GET to check by UUID if one was returned).

For 429 responses, retry with a fixed or exponential delay. Rate limit response headers are not yet returned.

La API de TreasuryHub devuelve objetos de error estructurados en toda respuesta no-2xx. Siempre reacciona al campo errorCode — los strings title y detail son legibles por humanos y pueden cambiar entre versiones.

Devuelto en fallos de autenticación, validación de encabezados y errores de infraestructura:

{
"status": 401,
"errorCode": "ERR-1002",
"title": "Invalid authentication token."
}

Devuelto cuando el cuerpo de la solicitud no pasa la validación. El errorCode de nivel raíz corresponde al primer fallo; el array errors lista todos los fallos de la solicitud:

{
"status": 400,
"errorCode": "ERR-3001",
"title": "One or more validation errors occurred.",
"errors": [
{
"field": "ExternalId",
"errorCode": "ERR-3001",
"message": "ExternalId is required."
},
{
"field": "Amount",
"errorCode": "ERR-3005",
"message": "Amount must be greater than 0."
}
]
}
CódigoHTTPCuándo ocurre
ERR-1001401Encabezado de autenticación ausente
ERR-1002401Token de autenticación inválido
ERR-1003403Autenticado pero sin autorización para el recurso
ERR-2001400Encabezado de tenant ausente
ERR-2002400Encabezado de tenant no es un UUID válido
ERR-3001400externalId está vacío o ausente
ERR-3002400type no es INTERNAL_PAYIN ni INTERNAL_PAYOUT
ERR-3003400countryCode no es un código ISO 3166-1 alpha-2 válido
ERR-3004400currencyCode no es un código ISO 4217 válido
ERR-3005400amount es cero o negativo
ERR-3006400status no es PENDING, REJECTED ni BOOKED
ERR-3007400Un multiCurrencyAmounts[].currencyCode no es un código ISO 4217 válido
ERR-3008400Un multiCurrencyAmounts[].amount es cero o negativo
ERR-3009400Campo exclusivo de payout enviado en un payload de payin
ERR-3010400Campo exclusivo de payin enviado en un payload de payout
ERR-3011400payload.channel no es CASH, ONLINE ni CRYPTO
ERR-4001400externalId ya existe para este tenant
ERR-4002404No se encontró ningún evento financiero con el UUID y tenant indicados
ERR-5001500Error interno inesperado

ERR-1001 / ERR-1002 — Errores de autenticación

Section titled “ERR-1001 / ERR-1002 — Errores de autenticación”

Verifica que toda solicitud incluya los tres encabezados requeridos:

X-Client-Id: {{tenant_id}}
X-Access-Token: {{access_token}}
Content-Type: application/json

ERR-1001 indica que falta un encabezado de autenticación requerido. ERR-1002 indica que el valor del token está presente pero es inválido — verifica que el token corresponde al entorno (th_live_ para Producción, th_test_ para Sandbox). Los tokens de un entorno no funcionan en el otro.


type debe ser exactamente INTERNAL_PAYIN o INTERNAL_PAYOUT — en mayúsculas, no se aceptan otras variantes.


ERR-3009 / ERR-3010 — Campos de payload incorrectos

Section titled “ERR-3009 / ERR-3010 — Campos de payload incorrectos”

El objeto payload tiene campos permitidos distintos según el tipo de evento:

  • INTERNAL_PAYIN: usa payerName, payerPersonalIdType, payerPersonalId.
  • INTERNAL_PAYOUT: usa beneficiaryName, beneficiaryPersonalIdType, beneficiaryPersonalId.

Enviar un campo del otro tipo causa un 400. Los campos desconocidos también son rechazados — el esquema del payload no permite additionalProperties.


externalId debe ser único por tenant. La API no tiene encabezado de idempotencia — si un POST ya devolvió 201, no lo reintentes con el mismo externalId.

Si la intención es actualizar un evento existente, usa PUT /api/h2h/ingestion/financial-events/{uuid} con el UUID devuelto por el POST original.


ERR-4002 — Evento financiero no encontrado

Section titled “ERR-4002 — Evento financiero no encontrado”

Verifica:

  1. El UUID en el path es el devuelto en el cuerpo del POST (campo uuid), no el externalId.
  2. El X-Client-Id corresponde al mismo tenant que creó el evento — las búsquedas entre tenants siempre devuelven 404.

Contacta al soporte de TreasuryHub con la solicitud completa y el timestamp. No reintentes automáticamente — vuelve a enviar el evento solo después de confirmar que el original no fue persistido.

async function llamarApi(url, opciones) {
const respuesta = await fetch(url, opciones);
if (respuesta.ok) return respuesta.json();
const error = await respuesta.json();
// Siempre ramifica por errorCode, no por estado HTTP ni por title
switch (error.errorCode) {
case 'ERR-4001':
throw new Error(`externalId duplicado — el evento ya existe.`);
case 'ERR-1001':
case 'ERR-1002':
throw new Error(`Autenticación fallida — verifica X-Client-Id y X-Access-Token.`);
default:
if (error.errors?.length) {
for (const e of error.errors) {
console.error(`[${e.errorCode}] ${e.field}: ${e.message}`);
}
}
throw new Error(`Error de API ${error.errorCode}: ${error.title}`);
}
}

La API de Financial Events usa externalId para deduplicación — no existe encabezado Idempotency-Key. Una solicitud que devuelve 201 no debe reintentarse con el mismo externalId. Una solicitud que devuelve 5xx o agota el tiempo de espera puede reintentarse con el mismo externalId solo si confirmaste que el evento no fue creado (usa GET para verificar por UUID si se devolvió alguno).

Para respuestas 429, reintenta con un retardo fijo o exponencial. Los encabezados de respuesta de límite de tasa aún no están disponibles.