Concepts
Response envelope
What the gateway returns: the transaction envelope for writes (status, transaction_id, module, data, idempotent_replay), the engine’s body for reads, and how each SDK’s models expose it.
On this page
The gateway responds in one of two ways, depending on the type of operation.
Writes: the transaction envelope #
Every operation that changes something (the ones that carry an Idempotency-Key) responds with the same envelope,
whatever the module:
{
"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
}| Field | What it is |
|---|---|
status | The gateway’s result (success). Failures don’t arrive here: they’re problem+json HTTP errors. |
transaction_id | The transaction id in the gateway. Store it: you’ll use it to check its status, reconcile and open cases with support. |
module | The module that processed it (credits, subsidies, wallet, loans, pqrs, health, admin, webhooks…). |
data | The engine’s body, as is: domain ids (application_id, payment_id…), statuses and amounts. |
idempotent_replay | Only appears (as true) when the response is the stored replay of an Idempotency-Key that was already used. |
Tip
Don’t confuse transaction_id (the gateway’s, in the envelope) with the domain ids inside
data (data.application_id, the wallet’s data.transaction_id, a webhook endpoint’s
data.id…). To decide on or disburse a credit you use the application_id, not the envelope’s
transaction_id.
Reads: the engine’s body #
GETs (and POSTs that only query: resolving a recipient, looking up a bill,
quoting FX, calculating taxes) return the engine’s object or list directly, with no envelope.
Lists are paginated (Pagination).
How the SDKs expose it #
Each SDK turns the envelope into a Transaction and, where it adds value, turns reads into typed
models (Balance, Resolution, AffiliateLookup, WebhookEndpoint, TestClock, Page…). Every
model keeps the original body in raw (Raw in .NET and Go) for the fields the SDK doesn’t type.
| Python | JavaScript / TS | PHP | .NET | Go | |
|---|---|---|---|---|---|
| Envelope | Transaction | Transaction | Compense\Sdk\Model\Transaction | Compense.Sdk.Models.Transaction | *compense.Transaction |
| Gateway id | tx.transaction_id | tx.transactionId | $tx->transactionId | tx.TransactionId | tx.TransactionID |
| Replay | tx.idempotent_replay | tx.idempotentReplay | $tx->idempotentReplay | tx.IdempotentReplay | tx.IdempotentReplay |
| Engine body | tx.data (dict) | tx.data (JsonObject) | $tx->data (array) | tx.Data (JsonObject) | tx.Data (map[string]any) |
| Reads without a model | dict | JsonObject | array | JsonObject | map[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"] # domain id, to decide and disburse
save(tx.transaction_id, app_id) # store bothconst tx = await client.credits.submitApplication({
affiliate: { document_type: "CC", document_number: "1000000001" },
productCode: "LIBRANZA_12M", amount: "3500000", termMonths: 12,
externalReference: "HORIZONTE-CRED-2026-000123",
});
const appId = String(tx.data.application_id);
await save(tx.transactionId, appId);use Compense\Sdk\Model\AffiliateRef;
$tx = $client->credits->submitApplication(
affiliate: new AffiliateRef('CC', '1000000001'),
productCode: 'LIBRANZA_12M', amount: '3500000', termMonths: 12,
externalReference: 'HORIZONTE-CRED-2026-000123',
);
$appId = $tx->data['application_id'];
save($tx->transactionId, $appId);Transaction tx = await client.Credits.SubmitApplicationAsync(
new AffiliateRef("CC", "1000000001"), "LIBRANZA_12M", "3500000", 12, "HORIZONTE-CRED-2026-000123");
string appId = (string)tx.Data["application_id"]!;
await SaveAsync(tx.TransactionId, appId);tx, err := client.Credits.SubmitApplication(ctx, &compense.CreditApplicationParams{
Affiliate: compense.AffiliateRef{DocumentType: "CC", DocumentNumber: "1000000001"},
ProductCode: "LIBRANZA_12M",
Amount: "3500000",
TermMonths: 12,
ExternalReference: "HORIZONTE-CRED-2026-000123",
})
if err != nil {
log.Fatal(err)
}
appID := fmt.Sprint(tx.Data["application_id"])
save(tx.TransactionID, appID)curl -s -X POST https://sandbox.dev.compense.co/gw/v1/gateway/credits/application/ \
-H "X-API-Key: $COMPENSE_API_KEY" -H "Idempotency-Key: horizonte-cred-2026-000123" \
-H "Content-Type: application/json" \
-d '{"afiliado":{"document_type":"CC","document_number":"1000000001"},"product_code":"LIBRANZA_12M","amount":"3500000","term_months":12,"external_reference":"HORIZONTE-CRED-2026-000123"}' \
| jq '{tx: .transaction_id, app: .data.application_id}'Useful response headers #
| Header | What it’s for |
|---|---|
X-Request-ID | The request id; matches the trace_id in errors. Log it. |
RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset | The state of your limit (Rate limits). |
Retry-After | On 429 (and some 5xx): seconds to wait. The SDKs honor it. |
Deprecation, Sunset, Link | The operation is deprecated (Deprecations). |