Pagos del API Bancario
API 1.0.0Una herramienta del MCP envuelve esta operación: Herramientas bancarias.
El grupo Payments cubre el ciclo completo de un pago: crearlo, consultarlo por
identificador, listarlo con filtros y buscarlo por cualquiera de sus referencias.
POST /api/public/v1/transactions/payments
GET /api/public/v1/transactions/payments
GET /api/public/v1/transactions/payments/{payment_id}
POST /api/public/v1/transactions/payments/searchReglas del recurso#
Métodos. payment_method_code admite PIN y SINPE_MOVIL. Dirección.
Al crear, direction solo admite OUT (salida); los pagos IN (entrada) siguen existiendo en listados y webhooks. Cuenta destino. se identifica por
IBAN o por PHONE, según el método. Validala antes de transferir con la
validación de cuentas.
Referencia propia. client_reference es tu identificador del pago y es único por
tenant: dos pagos del mismo cliente no pueden compartirlo. Sirve para buscar el pago sin
guardar el payment_id.
Reintentos seguros. La creación acepta Idempotency-Key; reenviar la misma llave con
el mismo cuerpo devuelve el pago original en vez de crear otro. Ver
reintentos seguros.
Estados#
Un pago recorre cinco estados: pending, processing, confirmed, posted y failed.
La reversión no es un estado: un pago revertido sigue en posted y se reconoce por
result: reversed y has_reversal: true, además del evento
payment.reversed. Consultá siempre esos dos campos
antes de dar un pago por definitivo.
Operaciones#
Listar pagos del cliente
GET /api/public/v1/transactions/payments
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>.
Lista REST simple de los pagos de una cuenta propia (IBAN).
Los filtros son parámetros de consulta. La titularidad (tenant_id, owner_type, owner_id) se deriva del token de acceso; no enviés filtros de titularidad.
Identificación de la cuenta (requerida): type + value (esquema de identificación + valor, ej. IBAN + el IBAN). No es la clasificación interna de la cuenta.
La paginación es por cursor (limit, cursor). Límite por defecto 20 (máximo 100).
status en la respuesta y como filtro usa el catálogo público en minúsculas (pending, processing, confirmed, posted, failed). Mismos valores que los webhooks. REST también devuelve status_detail (nombre operativo en mayúsculas).
Cada ítem incluye un result consolidado (succeeded, failed, reversed, pending) para conciliar cuando se perdió un webhook. status es solo el catálogo de procesamiento/ciclo de vida y no cambia a failed cuando un pago registrado se revierte después: usá result=reversed y has_reversal=true (webhook payment.reversed). error es null cuando no hay información de fallo; es un objeto solo cuando domain / platform está presente (result es failed o reversed), misma forma que payment.error del webhook payment.failed. source / destination usan null para account, name e identification desconocidos; los valores de cuenta son solo IBAN o PHONE (nunca UUID internos de cuenta). En pagos PIN, identification.number es el número público enviado por el comercio (sin guiones SINPE); los pagos antiguos aún pueden mostrar la forma SINPE con guiones.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
type | query | string | sí | Esquema de identificación de la cuenta (ej. IBAN).
No es la clasificación interna de la cuenta
(ej. operativa).Valores: IBAN |
value | query | string | sí | Valor del identificador de la cuenta (IBAN). Los espacios se ignoran. |
status | query | string | no | Filtro opcional por estado del pago. El catálogo público es en minúsculas:
pending, processing, confirmed, posted, failed.
Se aceptan alias en mayúsculas de los mismos valores. Valores históricos
como INITIATED equivalen a pending.Valores: pending, processing, confirmed, posted, failed |
date_from | query | string (date-time) | no | Límite inferior inclusivo para created_at. RFC 3339 (UTC Z u offset; fracciones de segundo opcionales). |
date_to | query | string (date-time) | no | Límite superior inclusivo para created_at. RFC 3339 (UTC Z u offset; fracciones de segundo opcionales). |
client_reference | query | string | no | Filtro por la referencia de cliente del comercio (coincidencia exacta con el valor enviado al crear el pago). |
currency | query | string | no | Filtro por moneda del pago (ISO 4217, ej. CRC). |
payment_method_code | query | string | no | Filtro por código público del método de pago.Valores: PIN, SINPE_MOVIL |
direction | query | string | no | Filtro por dirección del pago. Acepta los valores públicos OUT/IN o
PAYOUT/PAYIN (se normalizan internamente a payout/payin).Valores: OUT, IN, PAYOUT, PAYIN |
limit | query | integer | no | Tamaño de página (por defecto 20, máximo 100). |
cursor | query | string | no | Cursor opaco de la pagination.next_cursor de una respuesta anterior. |
Respuesta 200
La solicitud se procesó correctamente.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
schema_version | string | sí | Mismo valor que el schema_version del sobre del webhook (1.0.0). |
items | array<object> | sí | — |
items[].schema_version | string | sí | Versión del contrato de lectura de pagos. Mismo valor que el schema_version
del sobre del webhook (1.0.0) para payment.succeeded / payment.failed. |
items[].payment_id | string (uuid) | sí | UUID del pago devuelto al crearlo. Llave del pago para el comercio en
GET /transactions/payments/{payment_id} y en la búsqueda. No es un id
interno de cuenta. |
items[].public_id | string | no | Identificador público numérico del pago devuelto al crearlo. null si aún
no se asigna. No es un UUID interno de cuenta.
Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto.Puede ser null. |
items[].type | string | sí | Tipo de pago derivado de la dirección (PAYIN / PAYOUT). |
items[].payment_method_code | string | sí | Catálogo público de métodos de pago (PIN, SINPE_MOVIL). Mismos valores que en los webhooks.Valores: PIN, SINPE_MOVIL |
items[].status | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST
(crear, listar, obtener) y en webhooks (payment.status).
Los estados internos del ciclo de vida se consolidan:
- pending: iniciado, validado, aceptado
- processing: procesando, pendiente de procesamiento, registrando
- confirmed: confirmado por el riel, aún no registrado en el ledger
- posted: registrado en el ledger (se mantiene posted tras un reverso posterior)
- failed: fallido, rechazado, posting_failed, cancelado, expirado
Un reverso no es un estado. Usá result=reversed / has_reversal=true en REST
y el webhook payment.reversed.
El detalle operativo queda en status_detail (nombre interno en mayúsculas)
en crear/listar/obtener de REST. El webhook payment.failed usa error.platform.code
para distinguir fallos de registro de rechazos del proveedor.Valores: pending, processing, confirmed, posted, failed |
items[].status_detail | string | no | Estado operativo (interno) en mayúsculas, ej. VALIDATED,
POSTED, POSTING_FAILED. Complemento del catálogo público status.
Independiente de result (posted es el hito de débito/registro, no el éxito del proveedor). |
items[].result | string | sí | Resultado de negocio consolidado para conciliación (respaldo de los webhooks).
Independiente del status de procesamiento. Se deriva así: reversed cuando
has_reversal es true (prioridad más alta); succeeded cuando succeeded_at
está presente y no hay reverso; failed cuando el estado de procesamiento es
failed o posting_failed; si no, pending.
Un pago registrado (posted) que luego se revirtió tiene status=posted y result=reversed.Valores: succeeded, failed, reversed, pending |
items[].succeeded_at | string (date-time) | no | Marca de tiempo de confirmación de éxito del proveedor (RFC 3339 UTC, precisión de segundos, Z).
Null mientras el pago ya pueda estar posted internamente pero el proveedor no haya confirmado el éxito.Puede ser null. |
items[].has_reversal | boolean | sí | True cuando se aplicó un reverso. Independiente de status. Se correlaciona con el webhook payment.reversed. |
items[].reversed_at | string (date-time) | no | Cuándo se aplicó el reverso. Null cuando has_reversal es false.Puede ser null. |
items[].created_at | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
items[].updated_at | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
items[].amount | object | no | Misma forma monetaria que la creación de pago (PaymentAmount). |
items[].amount.amount | string | sí | — |
items[].amount.currency | string | sí | — |
items[].source | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes:
null cuando el valor se desconoce. account es un identificador público
(IBAN o PHONE); nunca se devuelven UUID internos de cuenta. |
items[].source.account | object | sí | Identificador público de la cuenta (type + value). null cuando el IBAN o
el teléfono no pueden resolverse. Nunca un UUID interno de cuenta.Puede ser null. |
items[].source.name | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, null.Puede ser null. |
items[].source.identification | object | sí | Identificación de la parte (clave de catálogo type + number). Objeto solo cuando
al menos un campo se conoce; si no, null. No expone los códigos internos
de tipo de SINPE (0–9); los tipos sin equivalencia se omiten (type: null).
number es el valor público enviado por el comercio (dígitos, sin guiones SINPE).
Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones.Puede ser null. |
items[].destination | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes:
null cuando el valor se desconoce. account es un identificador público
(IBAN o PHONE); nunca se devuelven UUID internos de cuenta. |
items[].destination.account | object | sí | Identificador público de la cuenta (type + value). null cuando el IBAN o
el teléfono no pueden resolverse. Nunca un UUID interno de cuenta.Puede ser null. |
items[].destination.name | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, null.Puede ser null. |
items[].destination.identification | object | sí | Identificación de la parte (clave de catálogo type + number). Objeto solo cuando
al menos un campo se conoce; si no, null. No expone los códigos internos
de tipo de SINPE (0–9); los tipos sin equivalencia se omiten (type: null).
number es el valor público enviado por el comercio (dígitos, sin guiones SINPE).
Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones.Puede ser null. |
items[].client_reference | string | no | Referencia del comercio enviada al crear el pago (estable después del procesamiento). Mismo campo que payment.client_reference del webhook. |
items[].external_reference | string | no | Rail/SINPE transaction id. Same field, location, and meaning as webhook
payment.external_reference on payment.succeeded / payment.failed
Sibling of
client_reference. null if none.Puede ser null. |
items[].provider | object | no | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook.
La referencia del riel solo está en payment.external_reference, no se duplica aquí.
Los provider_status_* coinciden con rejection.reason_code / message / code del webhook
cuando el proveedor rechazó la operación. null cuando no hay rechazo. |
items[].provider.correlation_id | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id.
Not channel_reference (e.g. MOBILE_APP). Distinct from webhook
event.correlation_id (HTTP request id for this delivery). null when unknown.Puede ser null. |
items[].provider.occurred_at | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
items[].provider.provider_status_code | string | sí | Motivo/código crudo del proveedor (ej. 31). Mismo significado que
rejection.reason_code del webhook. null cuando no hay rechazo del proveedor.Puede ser null. |
items[].provider.provider_status_desc | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que
rejection.message del webhook. null cuando no hay rechazo del proveedor.Puede ser null. |
items[].provider.provider_status_semantic | string | sí | Semántica normalizada de la plataforma (ej. ACCOUNT_BLOCKED). Mismo significado que
rejection.code del webhook. null cuando no hay rechazo del proveedor.Puede ser null. |
items[].error | object | no | Siempre presente. null cuando no hay información de fallo
(succeeded, pending, o failed/reversed sin taxonomía).
El objeto usa la misma forma domain / platform que el webhook payment.failed.Puede ser null. |
items[].error.domain | string | sí | Mismo catálogo que payment.error.domain del webhook.Valores: provider_rejection, platform_validation, platform_posting, platform_infra, platform_reversal |
items[].error.platform | object | sí | — |
pagination | object | no | Paginación por cursor. Pasá next_cursor como cursor en la siguiente solicitud. |
pagination.next_cursor | string | no | Cursor opaco de la página siguiente; se omite o va vacío cuando no hay más páginas |
pagination.limit | integer | no | Tamaño de página aplicado a esta respuesta |
Ejemplo de respuesta
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"schema_version": "1.0.0",
"items": [
{
"schema_version": "1.0.0",
"payment_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"public_id": "10234",
"type": "PAYOUT",
"payment_method_code": "PIN",
"status": "posted",
"status_detail": "POSTED",
"result": "succeeded",
"succeeded_at": "2026-01-15T12:00:00Z",
"has_reversal": false,
"reversed_at": null,
"created_at": "2026-01-15T12:00:00Z",
"updated_at": "2026-01-15T12:00:00Z",
"amount": {
"amount": "1000.00",
"currency": "CRC",
"fees": "0.00",
"taxes": "0.00"
},
"source": {
"account": {
"type": "IBAN",
"value": "CR26036900101010588061",
"currency": "CRC"
},
"name": "María González",
"identification": {
"type": "cedula",
"number": "0205620043"
}
},
"destination": {
"account": {
"type": "IBAN",
"value": "CR16010400000000000031",
"currency": "CRC"
},
"name": "Juan Perez",
"identification": {
"type": "cedula",
"number": "0101010101"
}
},
"client_reference": "INV-1001",
"external_reference": "SINPE-20260115-000123",
"provider": {
"correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"occurred_at": "2026-01-15T12:00:00Z",
"provider_status_code": "00",
"provider_status_desc": "Aprobada",
"provider_status_semantic": "SUCCESS"
},
"error": null
}
],
"pagination": {
"next_cursor": "",
"limit": 20
}
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request. Check the required fields and try again. |
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 403 | ACCOUNT_ACCESS_DENIED | The actor does not have access to the requested account. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 502 | PROVIDER_ERROR | Unable to complete the request with the payment provider. Please try again later. |
| 503 | SERVICE_UNAVAILABLE | A required service is temporarily unavailable. Please try again later. |
Crear pago
POST /api/public/v1/transactions/payments
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>. Acepta Idempotency-Key.
Crea un pago desde una cuenta origen interna autorizada. El procesamiento puede ser asíncrono; HTTP 201 no implica que el pago esté finalizado. source.identification.number y destination.identification.number se guardan en forma pública (los dígitos enviados, sin guiones SINPE) y se devuelven en las lecturas posteriores. La forma con guiones de SINPE solo se usa internamente y no es el contrato público. Idempotency-Key es opcional; si se omite, cada solicitud se trata como un intento nuevo. Un client_reference repetido devuelve 409 PAYMENT_DUPLICATE cuando un pago en curso o completado ya lo usa; un pago previo failed (o rechazado/cancelado/expirado) no bloquea reintentar con el mismo client_reference. Si se envía Idempotency-Key, la misma clave con el mismo cuerpo repite la respuesta anterior; un cuerpo distinto con la misma clave devuelve 409 IDEMPOTENCY_CONFLICT.
No hay doble control en la creación de pagos del API: el pago se procesa directamente si el token, los permisos y los datos son válidos. Solo se admite direction OUT. Aplican límites por transacción, diarios y mensuales, en monto y cantidad. Si se supera alguno, el procesamiento falla y el evento payment.failed notifica el resultado.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
Idempotency-Key | header | string | no | Clave opaca opcional para reintentos seguros. Si la omitís, cada llamada es un intento nuevo (los duplicados se detectan por client_reference en pagos en curso o completados). Reutilizar la clave con un cuerpo distinto devuelve 409. |
Cuerpo del request
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
payment_method_code | string | sí | Catálogo público de métodos de pago (PIN, SINPE_MOVIL).Valores: PIN, SINPE_MOVIL |
direction | string | sí | La creación solo acepta OUT (salida). Los pagos IN siguen disponibles en listados y webhooks.Valores: OUT |
country_code | string | no | País operativo cuando aplica multi-país |
amount | object | sí | — |
amount.amount | string | sí | Monto como texto decimal con exactamente 2 decimales (ej. "1000.00"). |
amount.currency | string | sí | Moneda ISO 4217 del pago.Valores: CRC, USD |
source | object | sí | — |
source.account | object | sí | — |
source.account.type | string | sí | Esquema de identificación de la cuenta. Aquí solo se admite IBAN.
No es la clasificación interna de la cuenta
(ej. operativa).Valores: IBAN |
source.account.value | string | sí | IBAN (se permiten espacios; se normaliza en el servidor) |
source.name | string | sí | Nombre del titular |
source.identification | object | sí | Identificación del beneficiario al crear un pago.
type usa las claves del catálogo de identificación de la plataforma (ej. cedula, juridica, dimex).
Mismo vocabulario que holder.id_type de POST /accounts/validate.
number es la identificación pública (dígitos, sin guiones SINPE). La plataforma
puede reformatearlo internamente para SINPE; esa forma interna no se devuelve en
las lecturas públicas de pagos.
Para SINPE_MOVIL, la validación de cuenta puede devolver unknown porque la consulta
del monedero no expone el tipo de identificación; no asumás un tipo confirmado. |
source.identification.type | string | no | Clave del catálogo de identificación (minúsculas), ej. cedula, juridica.
Puede copiarse de holder.id_type después de validar la cuenta.
Para SINPE_MOVIL ese valor puede ser unknown (limitación esperada, no un error).Valores: cedula, juridica, dimex, gobierno, institucion_autonoma, didi, pasaporte |
source.identification.number | string | no | Número de identificación público tal como lo envió el comercio.
Solo dígitos; no enviés la forma con guiones de SINPE (ej. 01-1234-3005)
ni tratés este campo como la forma interna de visualización SINPE.
Los tipos admitidos incluyen cedula, juridica, dimex, gobierno,
institucion_autonoma, didi y pasaporte. |
destination | object | sí | — |
destination.account | object | sí | — |
destination.account.type | string | sí | Esquema de identificación de la cuenta del beneficiario (IBAN para PIN, PHONE para SINPE_MOVIL).
No es la clasificación interna de la cuenta.Valores: IBAN, PHONE |
destination.account.value | string | sí | Cuando type es PHONE (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777").
Patrón para PHONE: ^\d{8}$. |
destination.name | string | sí | Nombre del beneficiario |
destination.identification | object | sí | Identificación del beneficiario al crear un pago.
type usa las claves del catálogo de identificación de la plataforma (ej. cedula, juridica, dimex).
Mismo vocabulario que holder.id_type de POST /accounts/validate.
number es la identificación pública (dígitos, sin guiones SINPE). La plataforma
puede reformatearlo internamente para SINPE; esa forma interna no se devuelve en
las lecturas públicas de pagos.
Para SINPE_MOVIL, la validación de cuenta puede devolver unknown porque la consulta
del monedero no expone el tipo de identificación; no asumás un tipo confirmado. |
destination.identification.type | string | no | Clave del catálogo de identificación (minúsculas), ej. cedula, juridica.
Puede copiarse de holder.id_type después de validar la cuenta.
Para SINPE_MOVIL ese valor puede ser unknown (limitación esperada, no un error).Valores: cedula, juridica, dimex, gobierno, institucion_autonoma, didi, pasaporte |
destination.identification.number | string | no | Número de identificación público tal como lo envió el comercio.
Solo dígitos; no enviés la forma con guiones de SINPE (ej. 01-1234-3005)
ni tratés este campo como la forma interna de visualización SINPE.
Los tipos admitidos incluyen cedula, juridica, dimex, gobierno,
institucion_autonoma, didi y pasaporte. |
detail_reference | string | sí | Descripción operativa / transaccional que se guarda en el pago |
client_reference | string | no | Referencia funcional del comercio. Única por comercio entre pagos en curso y completados; un intento fallido puede reintentarse con el mismo valor. |
channel_reference | string | no | — |
originator | object | no | Información opcional del ordenante (Ultimate Debtor / Travel Rule). Solo informativa en esta versión; no se aplica validación. Se guarda en los metadatos del pago cuando se envía.Puede ser null. |
originator.company | object | no | —Puede ser null. |
originator.company.legal_name | string | no | — |
originator.company.id_type | string | no | — |
originator.company.id_number | string | no | — |
originator.customer | object | no | —Puede ser null. |
originator.customer.name | string | no | — |
originator.customer.id_type | string | no | — |
originator.customer.id_number | string | no | — |
Ejemplo de request
{
"payment_method_code": "PIN",
"direction": "OUT",
"country_code": "CR",
"amount": {
"amount": "1000.00",
"currency": "CRC"
},
"source": {
"account": {
"type": "IBAN",
"value": "CR26036900101010588061"
},
"name": "María González",
"identification": {
"type": "cedula",
"number": "0205620043"
}
},
"destination": {
"account": {
"type": "IBAN",
"value": "CR16010400000000000031"
},
"name": "Juan Perez",
"identification": {
"type": "cedula",
"number": "0101010101"
}
},
"detail_reference": "Pago factura 1001",
"client_reference": "INV-1001",
"channel_reference": "MOBILE_APP"
}Respuesta 201
El recurso se creó correctamente.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
payment_id | string (uuid) | no | UUID interno del pago |
public_id | string | no | Identificador público numérico del pago Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. |
status | string | no | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST
(crear, listar, obtener) y en webhooks (payment.status).
Los estados internos del ciclo de vida se consolidan:
- pending: iniciado, validado, aceptado
- processing: procesando, pendiente de procesamiento, registrando
- confirmed: confirmado por el riel, aún no registrado en el ledger
- posted: registrado en el ledger (se mantiene posted tras un reverso posterior)
- failed: fallido, rechazado, posting_failed, cancelado, expirado
Un reverso no es un estado. Usá result=reversed / has_reversal=true en REST
y el webhook payment.reversed.
El detalle operativo queda en status_detail (nombre interno en mayúsculas)
en crear/listar/obtener de REST. El webhook payment.failed usa error.platform.code
para distinguir fallos de registro de rechazos del proveedor.Valores: pending, processing, confirmed, posted, failed |
status_detail | string | no | Detalle operativo del estado (ej. PROCESSING) |
payment_method_code | string | no | Catálogo público de métodos de pago (PIN, SINPE_MOVIL).Valores: PIN, SINPE_MOVIL |
created_at | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
Ejemplo de respuesta
{
"success": true,
"http_status_code": 201,
"response_code": "CREATED",
"message": "The resource was created successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"payment_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"public_id": "10234",
"status": "pending",
"status_detail": "PROCESSING",
"payment_method_code": "PIN",
"created_at": "2026-01-15T12:00:00Z"
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 400 | PAYMENT_INVALID_PAYLOAD | Invalid payment request payload. |
| 400 | INVALID_PAYMENT_METHOD | Invalid or unsupported payment method. |
| 400 | INVALID_ACCOUNT_TYPE | Unsupported or invalid account type. |
| 400 | ACCOUNT_INVALID | The account is invalid or not enabled for the service. |
| 400 | ACCOUNT_HOLDER_MISMATCH | Account holder does not match the provided identification or name. |
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 403 | ACCOUNT_ACCESS_DENIED | The actor does not have access to the requested account. |
| 404 | ACCOUNT_NOT_FOUND | Account not found. |
| 409 | IDEMPOTENCY_CONFLICT | Idempotency conflict: the same Idempotency-Key was reused with a different request body, or a previous request is still in progress. |
| 409 | PAYMENT_DUPLICATE | An in-flight or completed payment with this client_reference already exists. |
| 409 | CONFLICT | The request conflicts with the current state. |
| 422 | INSUFFICIENT_FUNDS | Insufficient funds to complete the payment. |
| 422 | LIMIT_EXCEEDED | A transaction or accumulation limit was exceeded. |
| 422 | UNPROCESSABLE_ENTITY | The request is well-formed but cannot be processed due to business rules. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 502 | PROVIDER_ERROR | Unable to complete the request with the payment provider. Please try again later. |
| 503 | SERVICE_UNAVAILABLE | A required service is temporarily unavailable. Please try again later. |
Buscar pago por identificador
POST /api/public/v1/transactions/payments/search
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>.
Busca un solo pago dentro de la cuenta del cliente indicada, por exactamente uno de:
payment_id(UUID interno)public_id(identificador público numérico)client_reference(referencia del comercio enviada al crear)
Enviar más de un identificador devuelve 400. La respuesta tiene la misma forma que la consulta por id (schema_version, external_reference a nivel de pago, objeto provider compartido, provider.provider_status_*, error alineado con el webhook). Mismo contrato público que GET /transactions/payments, incluido el identification.number público de los pagos PIN. Si varios pagos comparten un client_reference (intento fallido más reintento), se devuelve el pago en curso o completado cuando existe.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
Cuerpo del request
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
account | object | sí | — |
account.type | string | sí | Esquema de identificación de la cuenta (ej. IBAN, PHONE).
No es la clasificación interna de la cuenta (ej. operativa).Valores: IBAN, PHONE |
account.value | string | sí | Cuando type es PHONE (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). |
account.currency | string | no | Moneda opcional de la cuenta en las respuestas. |
payment_id | string (uuid) | no | UUID interno del pago. |
public_id | string | no | Identificador público numérico del pago. Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto. |
client_reference | string | no | Referencia del comercio enviada al crear el pago. |
Ejemplo de request
byPaymentId
{
"account": {
"type": "IBAN",
"value": "CR08036900101010933608"
},
"payment_id": "11111111-1111-1111-1111-111111111111"
}byPublicId
{
"account": {
"type": "IBAN",
"value": "CR08036900101010933608"
},
"public_id": "134729"
}byClientReference
{
"account": {
"type": "IBAN",
"value": "CR08036900101010933608"
},
"client_reference": "INV-01082"
}Respuesta 200
La solicitud se procesó correctamente.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
schema_version | string | sí | Versión del contrato de lectura de pagos. Mismo valor que el schema_version
del sobre del webhook (1.0.0) para payment.succeeded / payment.failed. |
payment_id | string (uuid) | sí | UUID del pago devuelto al crearlo. Llave del pago para el comercio en
GET /transactions/payments/{payment_id} y en la búsqueda. No es un id
interno de cuenta. |
public_id | string | no | Identificador público numérico del pago devuelto al crearlo. null si aún
no se asigna. No es un UUID interno de cuenta.
Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto.Puede ser null. |
type | string | sí | Tipo de pago derivado de la dirección (PAYIN / PAYOUT). |
payment_method_code | string | sí | Catálogo público de métodos de pago (PIN, SINPE_MOVIL). Mismos valores que en los webhooks.Valores: PIN, SINPE_MOVIL |
status | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST
(crear, listar, obtener) y en webhooks (payment.status).
Los estados internos del ciclo de vida se consolidan:
- pending: iniciado, validado, aceptado
- processing: procesando, pendiente de procesamiento, registrando
- confirmed: confirmado por el riel, aún no registrado en el ledger
- posted: registrado en el ledger (se mantiene posted tras un reverso posterior)
- failed: fallido, rechazado, posting_failed, cancelado, expirado
Un reverso no es un estado. Usá result=reversed / has_reversal=true en REST
y el webhook payment.reversed.
El detalle operativo queda en status_detail (nombre interno en mayúsculas)
en crear/listar/obtener de REST. El webhook payment.failed usa error.platform.code
para distinguir fallos de registro de rechazos del proveedor.Valores: pending, processing, confirmed, posted, failed |
status_detail | string | no | Estado operativo (interno) en mayúsculas, ej. VALIDATED,
POSTED, POSTING_FAILED. Complemento del catálogo público status.
Independiente de result (posted es el hito de débito/registro, no el éxito del proveedor). |
result | string | sí | Resultado de negocio consolidado para conciliación (respaldo de los webhooks).
Independiente del status de procesamiento. Se deriva así: reversed cuando
has_reversal es true (prioridad más alta); succeeded cuando succeeded_at
está presente y no hay reverso; failed cuando el estado de procesamiento es
failed o posting_failed; si no, pending.
Un pago registrado (posted) que luego se revirtió tiene status=posted y result=reversed.Valores: succeeded, failed, reversed, pending |
succeeded_at | string (date-time) | no | Marca de tiempo de confirmación de éxito del proveedor (RFC 3339 UTC, precisión de segundos, Z).
Null mientras el pago ya pueda estar posted internamente pero el proveedor no haya confirmado el éxito.Puede ser null. |
has_reversal | boolean | sí | True cuando se aplicó un reverso. Independiente de status. Se correlaciona con el webhook payment.reversed. |
reversed_at | string (date-time) | no | Cuándo se aplicó el reverso. Null cuando has_reversal es false.Puede ser null. |
created_at | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
updated_at | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
amount | object | no | Misma forma monetaria que la creación de pago (PaymentAmount). |
amount.amount | string | sí | — |
amount.currency | string | sí | — |
source | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes:
null cuando el valor se desconoce. account es un identificador público
(IBAN o PHONE); nunca se devuelven UUID internos de cuenta. |
source.account | object | sí | Identificador público de la cuenta (type + value). null cuando el IBAN o
el teléfono no pueden resolverse. Nunca un UUID interno de cuenta.Puede ser null. |
source.account.type | string | sí | Esquema de identificación de la cuenta (ej. IBAN, PHONE).
No es la clasificación interna de la cuenta (ej. operativa).Valores: IBAN, PHONE |
source.account.value | string | sí | Cuando type es PHONE (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). |
source.account.currency | string | no | Moneda opcional de la cuenta en las respuestas. |
source.name | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, null.Puede ser null. |
source.identification | object | sí | Identificación de la parte (clave de catálogo type + number). Objeto solo cuando
al menos un campo se conoce; si no, null. No expone los códigos internos
de tipo de SINPE (0–9); los tipos sin equivalencia se omiten (type: null).
number es el valor público enviado por el comercio (dígitos, sin guiones SINPE).
Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones.Puede ser null. |
source.identification.type | string | no | Clave del catálogo de identificación (ej. cedula, juridica). null cuando se desconoce.Puede ser null. |
source.identification.number | string | no | Número de identificación público. Los pagos PIN nuevos devuelven el valor enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE (con guiones, posiblemente con relleno).Puede ser null. |
destination | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes:
null cuando el valor se desconoce. account es un identificador público
(IBAN o PHONE); nunca se devuelven UUID internos de cuenta. |
destination.account | object | sí | Identificador público de la cuenta (type + value). null cuando el IBAN o
el teléfono no pueden resolverse. Nunca un UUID interno de cuenta.Puede ser null. |
destination.account.type | string | sí | Esquema de identificación de la cuenta (ej. IBAN, PHONE).
No es la clasificación interna de la cuenta (ej. operativa).Valores: IBAN, PHONE |
destination.account.value | string | sí | Cuando type es PHONE (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). |
destination.account.currency | string | no | Moneda opcional de la cuenta en las respuestas. |
destination.name | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, null.Puede ser null. |
destination.identification | object | sí | Identificación de la parte (clave de catálogo type + number). Objeto solo cuando
al menos un campo se conoce; si no, null. No expone los códigos internos
de tipo de SINPE (0–9); los tipos sin equivalencia se omiten (type: null).
number es el valor público enviado por el comercio (dígitos, sin guiones SINPE).
Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones.Puede ser null. |
destination.identification.type | string | no | Clave del catálogo de identificación (ej. cedula, juridica). null cuando se desconoce.Puede ser null. |
destination.identification.number | string | no | Número de identificación público. Los pagos PIN nuevos devuelven el valor enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE (con guiones, posiblemente con relleno).Puede ser null. |
client_reference | string | no | Referencia del comercio enviada al crear el pago (estable después del procesamiento). Mismo campo que payment.client_reference del webhook. |
external_reference | string | no | Rail/SINPE transaction id. Same field, location, and meaning as webhook
payment.external_reference on payment.succeeded / payment.failed
Sibling of
client_reference. null if none.Puede ser null. |
provider | object | no | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook.
La referencia del riel solo está en payment.external_reference, no se duplica aquí.
Los provider_status_* coinciden con rejection.reason_code / message / code del webhook
cuando el proveedor rechazó la operación. null cuando no hay rechazo. |
provider.correlation_id | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id.
Not channel_reference (e.g. MOBILE_APP). Distinct from webhook
event.correlation_id (HTTP request id for this delivery). null when unknown.Puede ser null. |
provider.occurred_at | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
provider.provider_status_code | string | sí | Motivo/código crudo del proveedor (ej. 31). Mismo significado que
rejection.reason_code del webhook. null cuando no hay rechazo del proveedor.Puede ser null. |
provider.provider_status_desc | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que
rejection.message del webhook. null cuando no hay rechazo del proveedor.Puede ser null. |
provider.provider_status_semantic | string | sí | Semántica normalizada de la plataforma (ej. ACCOUNT_BLOCKED). Mismo significado que
rejection.code del webhook. null cuando no hay rechazo del proveedor.Puede ser null. |
error | object | no | Siempre presente. null cuando no hay información de fallo
(succeeded, pending, o failed/reversed sin taxonomía).
El objeto usa la misma forma domain / platform que el webhook payment.failed.Puede ser null. |
error.domain | string | sí | Mismo catálogo que payment.error.domain del webhook.Valores: provider_rejection, platform_validation, platform_posting, platform_infra, platform_reversal |
error.platform | object | sí | — |
error.platform.code | string | sí | Código público estable de la plataforma (igual que payment.error.platform.code del webhook). |
error.platform.message | string | sí | Mensaje accionable (prefiere el Detalle del proveedor). Igual que payment.error.platform.message del webhook. |
Ejemplo de respuesta
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"schema_version": "1.0.0",
"payment_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"public_id": "10234",
"type": "PAYOUT",
"payment_method_code": "PIN",
"status": "posted",
"status_detail": "POSTED",
"result": "succeeded",
"succeeded_at": "2026-01-15T12:00:00Z",
"has_reversal": false,
"reversed_at": null,
"created_at": "2026-01-15T12:00:00Z",
"updated_at": "2026-01-15T12:00:00Z",
"amount": {
"amount": "1000.00",
"currency": "CRC",
"fees": "0.00",
"taxes": "0.00"
},
"source": {
"account": {
"type": "IBAN",
"value": "CR26036900101010588061",
"currency": "CRC"
},
"name": "María González",
"identification": {
"type": "cedula",
"number": "0205620043"
}
},
"destination": {
"account": {
"type": "IBAN",
"value": "CR16010400000000000031",
"currency": "CRC"
},
"name": "Juan Perez",
"identification": {
"type": "cedula",
"number": "0101010101"
}
},
"client_reference": "INV-1001",
"external_reference": "SINPE-20260115-000123",
"provider": {
"correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"occurred_at": "2026-01-15T12:00:00Z",
"provider_status_code": "00",
"provider_status_desc": "Aprobada",
"provider_status_semantic": "SUCCESS"
},
"error": null
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request. Check the required fields and try again. |
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 403 | ACCOUNT_ACCESS_DENIED | The actor does not have access to the requested account. |
| 404 | PAYMENT_NOT_FOUND | Payment not found. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 502 | PROVIDER_ERROR | Unable to complete the request with the payment provider. Please try again later. |
| 503 | SERVICE_UNAVAILABLE | A required service is temporarily unavailable. Please try again later. |
Obtener pago por id
GET /api/public/v1/transactions/payments/{payment_id}
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>.
Devuelve un solo pago con el mismo contrato público del listado, incluidos el result consolidado, succeeded_at, has_reversal y error. error es null cuando no hay información de fallo; es un objeto solo cuando domain / platform está presente (result es failed o reversed), misma forma que payment.error del webhook payment.failed. source / destination usan null para campos anidados desconocidos y nunca exponen UUID internos de cuenta. identification.number en pagos PIN es el número público enviado por el comercio (dígitos, sin guiones SINPE). Los pagos antiguos aún pueden devolver la forma SINPE con guiones. Usalo como respaldo de los webhooks.
Busca un pago por cualquiera de estos identificadores:
payment_id(UUID interno)public_id(identificador público numérico)
Para client_reference, usá POST /api/public/v1/transactions/payments/search.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
payment_id | path | string | sí | UUID interno del pago o public_id numérico. |
Respuesta 200
La solicitud se procesó correctamente.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
schema_version | string | sí | Versión del contrato de lectura de pagos. Mismo valor que el schema_version
del sobre del webhook (1.0.0) para payment.succeeded / payment.failed. |
payment_id | string (uuid) | sí | UUID del pago devuelto al crearlo. Llave del pago para el comercio en
GET /transactions/payments/{payment_id} y en la búsqueda. No es un id
interno de cuenta. |
public_id | string | no | Identificador público numérico del pago devuelto al crearlo. null si aún
no se asigna. No es un UUID interno de cuenta.
Es el mismo identificador: número en webhooks y texto en REST. Tratalo siempre como texto.Puede ser null. |
type | string | sí | Tipo de pago derivado de la dirección (PAYIN / PAYOUT). |
payment_method_code | string | sí | Catálogo público de métodos de pago (PIN, SINPE_MOVIL). Mismos valores que en los webhooks.Valores: PIN, SINPE_MOVIL |
status | string | sí | Catálogo público de estados del pago. Siempre en minúsculas. Mismos valores en REST
(crear, listar, obtener) y en webhooks (payment.status).
Los estados internos del ciclo de vida se consolidan:
- pending: iniciado, validado, aceptado
- processing: procesando, pendiente de procesamiento, registrando
- confirmed: confirmado por el riel, aún no registrado en el ledger
- posted: registrado en el ledger (se mantiene posted tras un reverso posterior)
- failed: fallido, rechazado, posting_failed, cancelado, expirado
Un reverso no es un estado. Usá result=reversed / has_reversal=true en REST
y el webhook payment.reversed.
El detalle operativo queda en status_detail (nombre interno en mayúsculas)
en crear/listar/obtener de REST. El webhook payment.failed usa error.platform.code
para distinguir fallos de registro de rechazos del proveedor.Valores: pending, processing, confirmed, posted, failed |
status_detail | string | no | Estado operativo (interno) en mayúsculas, ej. VALIDATED,
POSTED, POSTING_FAILED. Complemento del catálogo público status.
Independiente de result (posted es el hito de débito/registro, no el éxito del proveedor). |
result | string | sí | Resultado de negocio consolidado para conciliación (respaldo de los webhooks).
Independiente del status de procesamiento. Se deriva así: reversed cuando
has_reversal es true (prioridad más alta); succeeded cuando succeeded_at
está presente y no hay reverso; failed cuando el estado de procesamiento es
failed o posting_failed; si no, pending.
Un pago registrado (posted) que luego se revirtió tiene status=posted y result=reversed.Valores: succeeded, failed, reversed, pending |
succeeded_at | string (date-time) | no | Marca de tiempo de confirmación de éxito del proveedor (RFC 3339 UTC, precisión de segundos, Z).
Null mientras el pago ya pueda estar posted internamente pero el proveedor no haya confirmado el éxito.Puede ser null. |
has_reversal | boolean | sí | True cuando se aplicó un reverso. Independiente de status. Se correlaciona con el webhook payment.reversed. |
reversed_at | string (date-time) | no | Cuándo se aplicó el reverso. Null cuando has_reversal es false.Puede ser null. |
created_at | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
updated_at | string (date-time) | no | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
amount | object | no | Misma forma monetaria que la creación de pago (PaymentAmount). |
amount.amount | string | sí | — |
amount.currency | string | sí | — |
source | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes:
null cuando el valor se desconoce. account es un identificador público
(IBAN o PHONE); nunca se devuelven UUID internos de cuenta. |
source.account | object | sí | Identificador público de la cuenta (type + value). null cuando el IBAN o
el teléfono no pueden resolverse. Nunca un UUID interno de cuenta.Puede ser null. |
source.account.type | string | sí | Esquema de identificación de la cuenta (ej. IBAN, PHONE).
No es la clasificación interna de la cuenta (ej. operativa).Valores: IBAN, PHONE |
source.account.value | string | sí | Cuando type es PHONE (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). |
source.account.currency | string | no | Moneda opcional de la cuenta en las respuestas. |
source.name | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, null.Puede ser null. |
source.identification | object | sí | Identificación de la parte (clave de catálogo type + number). Objeto solo cuando
al menos un campo se conoce; si no, null. No expone los códigos internos
de tipo de SINPE (0–9); los tipos sin equivalencia se omiten (type: null).
number es el valor público enviado por el comercio (dígitos, sin guiones SINPE).
Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones.Puede ser null. |
source.identification.type | string | no | Clave del catálogo de identificación (ej. cedula, juridica). null cuando se desconoce.Puede ser null. |
source.identification.number | string | no | Número de identificación público. Los pagos PIN nuevos devuelven el valor enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE (con guiones, posiblemente con relleno).Puede ser null. |
destination | object | no | Parte del pago en las lecturas del API. Los campos anidados siempre están presentes:
null cuando el valor se desconoce. account es un identificador público
(IBAN o PHONE); nunca se devuelven UUID internos de cuenta. |
destination.account | object | sí | Identificador público de la cuenta (type + value). null cuando el IBAN o
el teléfono no pueden resolverse. Nunca un UUID interno de cuenta.Puede ser null. |
destination.account.type | string | sí | Esquema de identificación de la cuenta (ej. IBAN, PHONE).
No es la clasificación interna de la cuenta (ej. operativa).Valores: IBAN, PHONE |
destination.account.value | string | sí | Cuando type es PHONE (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). |
destination.account.currency | string | no | Moneda opcional de la cuenta en las respuestas. |
destination.name | string | sí | Nombre de la parte según los datos de procesamiento cuando está disponible; si no, null.Puede ser null. |
destination.identification | object | sí | Identificación de la parte (clave de catálogo type + number). Objeto solo cuando
al menos un campo se conoce; si no, null. No expone los códigos internos
de tipo de SINPE (0–9); los tipos sin equivalencia se omiten (type: null).
number es el valor público enviado por el comercio (dígitos, sin guiones SINPE).
Los pagos históricos aún pueden devolver la forma de visualización SINPE con guiones.Puede ser null. |
destination.identification.type | string | no | Clave del catálogo de identificación (ej. cedula, juridica). null cuando se desconoce.Puede ser null. |
destination.identification.number | string | no | Número de identificación público. Los pagos PIN nuevos devuelven el valor enviado por el comercio (dígitos, sin guiones SINPE). Los pagos históricos aún pueden devolver la forma de visualización SINPE (con guiones, posiblemente con relleno).Puede ser null. |
client_reference | string | no | Referencia del comercio enviada al crear el pago (estable después del procesamiento). Mismo campo que payment.client_reference del webhook. |
external_reference | string | no | Rail/SINPE transaction id. Same field, location, and meaning as webhook
payment.external_reference on payment.succeeded / payment.failed
Sibling of
client_reference. null if none.Puede ser null. |
provider | object | no | Foto compartida del proveedor en las lecturas REST de pagos y en los sobres de webhook.
La referencia del riel solo está en payment.external_reference, no se duplica aquí.
Los provider_status_* coinciden con rejection.reason_code / message / code del webhook
cuando el proveedor rechazó la operación. null cuando no hay rechazo. |
provider.correlation_id | string | sí | Provider transaction correlation identifier. Sent to SINPE as the correlation id.
Not channel_reference (e.g. MOBILE_APP). Distinct from webhook
event.correlation_id (HTTP request id for this delivery). null when unknown.Puede ser null. |
provider.occurred_at | string (date-time) | sí | Marca de tiempo RFC 3339 en UTC con precisión de segundos y sufijo Z.
Nunca se emiten fracciones de segundo. Ejemplo: 2026-01-15T12:00:00Z. |
provider.provider_status_code | string | sí | Motivo/código crudo del proveedor (ej. 31). Mismo significado que
rejection.reason_code del webhook. null cuando no hay rechazo del proveedor.Puede ser null. |
provider.provider_status_desc | string | sí | Texto Motivo del proveedor (prefiere Detalle). Mismo significado que
rejection.message del webhook. null cuando no hay rechazo del proveedor.Puede ser null. |
provider.provider_status_semantic | string | sí | Semántica normalizada de la plataforma (ej. ACCOUNT_BLOCKED). Mismo significado que
rejection.code del webhook. null cuando no hay rechazo del proveedor.Puede ser null. |
error | object | no | Siempre presente. null cuando no hay información de fallo
(succeeded, pending, o failed/reversed sin taxonomía).
El objeto usa la misma forma domain / platform que el webhook payment.failed.Puede ser null. |
error.domain | string | sí | Mismo catálogo que payment.error.domain del webhook.Valores: provider_rejection, platform_validation, platform_posting, platform_infra, platform_reversal |
error.platform | object | sí | — |
error.platform.code | string | sí | Código público estable de la plataforma (igual que payment.error.platform.code del webhook). |
error.platform.message | string | sí | Mensaje accionable (prefiere el Detalle del proveedor). Igual que payment.error.platform.message del webhook. |
Ejemplo de respuesta
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"schema_version": "1.0.0",
"payment_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"public_id": "10234",
"type": "PAYOUT",
"payment_method_code": "PIN",
"status": "posted",
"status_detail": "POSTED",
"result": "succeeded",
"succeeded_at": "2026-01-15T12:00:00Z",
"has_reversal": false,
"reversed_at": null,
"created_at": "2026-01-15T12:00:00Z",
"updated_at": "2026-01-15T12:00:00Z",
"amount": {
"amount": "1000.00",
"currency": "CRC",
"fees": "0.00",
"taxes": "0.00"
},
"source": {
"account": {
"type": "IBAN",
"value": "CR26036900101010588061",
"currency": "CRC"
},
"name": "María González",
"identification": {
"type": "cedula",
"number": "0205620043"
}
},
"destination": {
"account": {
"type": "IBAN",
"value": "CR16010400000000000031",
"currency": "CRC"
},
"name": "Juan Perez",
"identification": {
"type": "cedula",
"number": "0101010101"
}
},
"client_reference": "INV-1001",
"external_reference": "SINPE-20260115-000123",
"provider": {
"correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"occurred_at": "2026-01-15T12:00:00Z",
"provider_status_code": "00",
"provider_status_desc": "Aprobada",
"provider_status_semantic": "SUCCESS"
},
"error": null
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request. Check the required fields and try again. |
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 403 | ACCOUNT_ACCESS_DENIED | The actor does not have access to the requested account. |
| 404 | PAYMENT_NOT_FOUND | Payment not found. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 502 | PROVIDER_ERROR | Unable to complete the request with the payment provider. Please try again later. |
| 503 | SERVICE_UNAVAILABLE | A required service is temporarily unavailable. Please try again later. |
Procesamiento y límites#
La creación de pagos en el API no tiene doble control: el pago se procesa directamente si el token, los permisos y los datos son válidos. Aplican límites por transacción, diarios y mensuales, en monto y cantidad. Si se supera alguno, el pago falla durante el procesamiento y se notifica con el evento payment.failed.
El flujo de confirmación de transferencias del servidor MCP es independiente de esta creación directa del API.
Última verificación: 2026-10-22