El gateway responde de dos formas, según el tipo de operación.

Escrituras: el sobre de transacción #

Toda operación que cambia algo (las que llevan Idempotency-Key) responde con el mismo sobre, sea del módulo que sea:

JSON
{
  "status": "success",
  "transaction_id": "a1b2c3d4-0000-4a1b-9c2d-000000000001",
  "module": "wallet",
  "data": {
    "transaction_id": "9a8b…",
    "status": "COMPLETED",
    "amount": "30000.00",
    "currency": "COP"
  },
  "idempotent_replay": true
}
CampoQué es
statusResultado del gateway (success). Los fallos no llegan aquí: son errores HTTP problem+json.
transaction_idId de la transacción en el gateway. Guárdalo: sirve para consultar su estado, conciliar y abrir casos con soporte.
moduleMódulo que la procesó (credits, subsidies, wallet, loans, pqrs, health, admin, webhooks…).
dataEl cuerpo del motor, tal cual: ids del dominio (application_id, payment_id…), estados y montos.
idempotent_replaySolo aparece (en true) cuando la respuesta es la repetición guardada de una Idempotency-Key ya usada.

Consejo

No confundas transaction_id (del gateway, en el sobre) con los ids del dominio que vienen dentro de data (data.application_id, el data.transaction_id de la billetera, el data.id de un endpoint de webhook…). Para decidir o desembolsar un crédito usas el application_id, no el transaction_id del sobre.

Lecturas: el cuerpo del motor #

Los GET (y los POST que solo consultan: resolver un destinatario, consultar una factura, cotizar FX, calcular impuestos) devuelven directamente el objeto o la lista del motor, sin sobre. Las listas vienen paginadas (Paginación).

Cómo lo exponen los SDK #

Cada SDK convierte el sobre en un Transaction y, donde aporta, convierte las lecturas en modelos tipados (Balance, Resolution, AffiliateLookup, WebhookEndpoint, TestClock, Page…). Todo modelo conserva el cuerpo original en raw (Raw en .NET y Go) para los campos que el SDK no tipa.

PythonJavaScript / TSPHP.NETGo
SobreTransactionTransactionCompense\Sdk\Model\TransactionCompense.Sdk.Models.Transaction*compense.Transaction
Id del gatewaytx.transaction_idtx.transactionId$tx->transactionIdtx.TransactionIdtx.TransactionID
Repeticióntx.idempotent_replaytx.idempotentReplay$tx->idempotentReplaytx.IdempotentReplaytx.IdempotentReplay
Cuerpo del motortx.data (dict)tx.data (JsonObject)$tx->data (array)tx.Data (JsonObject)tx.Data (map[string]any)
Lecturas sin modelodictJsonObjectarrayJsonObjectmap[string]any
tx = client.credits.submit_application(
    affiliate={"document_type": "CC", "document_number": "1000000001"},
    product_code="LIBRANZA_12M", amount="3500000", term_months=12,
    external_reference="HORIZONTE-CRED-2026-000123",
)
app_id = tx.data["application_id"]      # id del dominio, para decidir y desembolsar
save(tx.transaction_id, app_id)         # guarda ambos

Cabeceras útiles de la respuesta #

CabeceraPara qué
X-Request-IDId de la petición; coincide con el trace_id de los errores. Regístralo.
RateLimit-Limit, RateLimit-Remaining, RateLimit-ResetEstado de tu límite (Límites de tasa).
Retry-AfterEn 429 (y algunos 5xx): segundos a esperar. Los SDK lo respetan.
Deprecation, Sunset, LinkLa operación está deprecada (Deprecaciones).