Keys and environments #

Where do I put the id of my family compensation fund (caja de compensación) or my entity? #

Nowhere. The cmp_... key identifies the tenant; the gateway resolves it on its own. Affiliates, patients or account holders are identified by their document.

I’m calling the sandbox URL and something real was executed. Why? #

Because what decides whether the response is simulated or real is the key, not the URL. A production key reaches the real engine at any URL. Keep separate keys per environment (Environments and keys).

I get a 403 with a key that used to work. #

It may be revoked or expired, it may be missing the scope for that operation, your organization may not have the module under contract, or your IP may not be on the allowlist. Call system.health() to see the scopes and read detail (Authentication).

What’s the production URL? #

The one declared in the contract is https://api.compense.co; the final one is confirmed during onboarding. Pass it as the base URL if it differs.

Idempotency and errors #

Do I have to send Idempotency-Key? #

Yes, on every write. It’s required for P2P, Bre-B, bill payments and top-ups (without it, 400). The SDKs generate one if you don’t provide it, but you should use a stable one per business operation (Idempotency).

I got IdempotencyConflictError but I didn’t reuse any key. #

The SDKs turn every 409 into that exception, and the engine uses 409 for business rejections (BILL_ALREADY_PAID, SLOT_NOT_AVAILABLE, REFERENCE_REUSED…). If problem.type doesn’t end in /idempotency-conflict, it’s a rejection: read detail (Errors).

My request timed out. Did it go through or not? #

You can’t know, and that’s exactly why idempotency exists: resend it with the same Idempotency-Key. If it already went through, you’ll get the stored response with idempotent_replay: true.

Why doesn’t the SDK retry my writes? #

Because it can’t know whether the gateway in front of it deduplicates, and retrying against one that doesn’t would duplicate the operation. Enable it with retry_writes once you know (Retries).

What do I send to support when something fails? #

The error’s trace_id (the same as the X-Request-ID header), the time, the operation and your Idempotency-Key. Never the key or full personal data.

Amounts #

Do I send amounts as numbers? #

No: as decimal strings ("467009.88"). The SDKs accept integers, decimals or strings and send the exact string (Amounts).

Webhooks #

The signature never matches. #

It’s almost always because you’re verifying a re-serialized body. Compute the HMAC over the raw bytes you received (in Express, express.raw(); in Laravel, $request->getContent(); in ASP.NET Core, copy Request.Body) and use the secret as UTF-8 text (Verify the signature).

I’m receiving the same event twice. #

Delivery is at least once: deduplicate by X-Webhook-Id (event_id). Respond with 2xx in under 10 seconds and process in the background to avoid unnecessary retries.

I lost my endpoint’s secret. #

It can’t be recovered: rotate it. The old one stops working immediately, so first deploy a receiver that accepts both (Rotate the secret).

Do I get real webhooks in the sandbox? #

No: in the sandbox, tests and redeliveries are simulated ("simulated": true). For real signed deliveries, use the dev environment with a production key (Test webhooks).

Sandbox #

Which documents do I use for testing? #

1000000001 (eligible), 1000000002 (ineligible), 1000000003 (manual review), 1000000004 (with debts) and 9999999999 (doesn’t exist), among others per module (Test data).

Are affiliates simulated? #

No. Affiliate lookup, cross-check and upload use your tenant’s real registry with any key.

SDK #

Which SDK should I use? #

The one for your language: all five cover the 115 operations with the same rules (SDKs). If your language doesn’t have an SDK, use plain HTTP with the API reference.

Do the SDKs sign high-value requests (X-Compense-Signature)? #

Not in version 1.1.0. If your key has signing enabled, add the header with your own HTTP client (Authentication).