Sandbox
The compense CLI
The webhooks and sandbox console bundled with the Python and JavaScript SDKs: health, events, endpoints, endpoint-create, trigger, deliveries, replay, clock, simulate and listen, with their exact options, variables and exit codes.
On this page
compense is a command-line tool for the tasks you do by hand while you integrate: validating a key,
browsing the event catalog, registering an endpoint, triggering a test event, reviewing and retrying
deliveries, moving a test clock, advancing a simulator and forwarding webhooks to your machine. Each
command is a thin wrapper over the SDK and prints the gateway’s response as JSON, so you can pipe
it into jq.
Installation #
The CLI is bundled with two SDKs, with the same commands and options. Use it even if your integration is in PHP, .NET or Go: those SDKs don’t ship a CLI.
| SDK | How to install | How to run |
|---|---|---|
| Python (3.9+) | pip install compense-sdk-python | compense … (it lands on the environment’s PATH) |
| JavaScript (Node 18+) | npm install @compense/sdk | npx compense … |
compense --help # Python and JavaScript
npx compense --version # JavaScript only: prints the SDK versionKey, environment and URL #
Every command that calls the API accepts three options:
| Option | Value | Default |
|---|---|---|
--key KEY | Your cmp_... key | The COMPENSE_API_KEY environment variable |
--environment ENV | production, sandbox or dev | sandbox |
--base-url URL | Any other gateway URL (e.g. the one you got during onboarding); takes precedence over --environment | — |
export COMPENSE_API_KEY="cmp_..." # PowerShell: $env:COMPENSE_API_KEY = "cmp_..."
compense health # sandbox by default
compense health --environment dev
compense health --base-url https://sandbox.dev.compense.co/gwRemember that the key decides the behavior: with a sandbox key you get sandbox responses in any
environment. Put the options after the command (and after its action, for clock and
simulate): that’s the form both implementations accept.
Output and exit codes #
- The response goes to stdout as indented JSON. SDK models are printed with the body exactly as the gateway returned it.
- Messages (errors, the
triggernotice) go to stderr.
| Code | Meaning |
|---|---|
0 | Success. |
1 | The gateway rejected the request (error: gateway rejected the request — …), or you ran compense without a command (it prints the help). In JavaScript, also a connection error or timeout, and an unknown or incomplete command. |
2 | No key (error: no API key. Pass --key or set $COMPENSE_API_KEY.), a configuration error (e.g. trigger with no active endpoints) or invalid options. In Python, also an unknown or incomplete command (an argparse error). |
Commands #
| Command | What it does | Operation |
|---|---|---|
health | Validates the key: tenant and scopes | GET/v1/gateway/health/ |
events [--category C] | Webhook event catalog | GET/v1/gateway/webhooks/event-catalog/ |
endpoints | Your endpoints (without the secret) | GET/v1/gateway/webhooks/endpoints/ |
endpoint-create --url U --event E [--event E …] [--label L] | Registers an endpoint and prints the secret once | POST/v1/gateway/webhooks/endpoints/ |
trigger <event> [--endpoint ID] | Sends a signed test delivery | POST/v1/gateway/webhooks/endpoints/{endpoint_id}/test/ |
deliveries [--status S] [--event-type T] [--endpoint ID] | Delivery history (first page) | GET/v1/gateway/webhooks/deliveries/ |
replay <delivery_id> | Retries a failed or abandoned delivery | POST/v1/gateway/webhooks/deliveries/{delivery_id}/replay/ |
clock create <frozen_time> | Creates a test clock | POST/v1/gateway/sandbox/test-clocks/ |
clock get <clock_id> | Retrieves a clock | GET/v1/gateway/sandbox/test-clocks/{clock_id}/ |
clock advance <clock_id> <seconds> | Moves a clock forward (prints the new id) | POST/v1/gateway/sandbox/test-clocks/{clock_id}/advance/ |
simulate transfer [--status S] [--amount A] [--transaction-id T] | One step of a wallet transfer | POST/v1/gateway/sandbox/wallet/simulate/ |
simulate credit <app_id> [--status S] [--amount A] | One step of a credit disbursement | POST/v1/gateway/sandbox/credits/{app_id}/advance/ |
listen --forward-to URL [--port N] | Forwards received webhooks to a local URL | — (doesn’t call the API) |
The CLI has no commands to edit, pause, delete or rotate endpoints, or to get a single delivery’s details: use the SDK or cURL (Subscribing an endpoint, Retries and deliveries).
health #
compense health{
"status": "ok",
"tenant": "horizonte",
"scopes": ["affiliates:read", "credits:submit", "webhooks:read", "webhooks:manage"]
}Webhooks #
# Catalog (everything or one category: credits, subsidies, monetary_allowance, affiliates,
# wallets, loans, health, admin, pqrs, general)
compense events --category loans
# Register an endpoint: repeat --event for each event. Save the "secret" it prints.
compense endpoint-create \
--url https://erp.horizonte.example/compense/webhooks \
--event payment.received \
--event installment.overdue \
--label "ERP Caja Horizonte"
compense endpoints
# Signed test. Without --endpoint it picks an active endpoint subscribed to the event
# (or, if there isn't one, the first active one).
compense trigger payment.received
compense trigger test.ping --endpoint 3f1a2b3c-0000-4a1b-9c2d-000000000001
# Failed deliveries for one event and a retry of one of them
compense deliveries --status failed --event-type payment.received
compense replay 8b7c6d5e-0000-4a1b-9c2d-000000000301deliveries shows the first page (25 deliveries) and has no date or page filter; to walk the
whole history, use the SDK, as in
Reprocessing every failed delivery. With jq
you can retry what you see:
compense deliveries --status failed | jq -r '.results[].id' | while read -r ID; do
compense replay "$ID"
doneClocks #
compense clock create 2026-10-01T00:00:00Z # or Unix seconds: 1790812800
compense clock advance tcl-… 2592000 # 30 days; prints the clock with a NEW id
compense clock get tcl-…
# Chain advances with jq
ID=$(compense clock create 2026-07-15T00:00:00Z | jq -r .id)
ID=$(compense clock advance "$ID" 5443200 | jq -r .id) # 63 days (maximum per call)
compense clock get "$ID" | jq -r .current_timeClocks only respond to sandbox keys. Details in Test clocks.
Simulators #
# Transfer: without --status it starts at PENDING. 22.22 → FAILED, 33.33 → RETURNED.
compense simulate transfer --amount 33.33
compense simulate transfer --status PROCESSING --amount 33.33
compense simulate transfer --status SETTLED --amount 33.33 --transaction-id NOVA-P2P-2026-000123
# Disbursement of a sandbox credit application
compense simulate credit sbx-E-… --status PENDING{
"object": "wallet_transfer",
"previous_status": "SETTLED",
"status": "RETURNED",
"terminal": true,
"amount": 33.33,
"reference": "NOVA-P2P-2026-000123",
"reason_code": "TRANSFER_RETURNED",
"environment": "sandbox"
}Details in Lifecycle simulators.
listen #
listen starts a server on 127.0.0.1 (port 8787 by default) that receives webhook deliveries and
forwards them as is (raw body and headers, except hop-by-hop ones such as Host or
Content-Length) to the URL you give it. It prints each delivery’s signature headers and returns to
Compense the same code your receiver answered with (or 502 if it can’t reach it), so retries
reflect what actually happened. Stop it with Ctrl-C.
compense listen --forward-to http://localhost:8000/compense/webhooks --port 8787listen doesn’t use the key and doesn’t accept --key, --environment or --base-url: it only
forwards. Since the sandbox doesn’t send webhooks and an endpoint must be public HTTPS, you need a
tunnel and a production key in the dev environment; the step-by-step guide is in
Testing your webhooks.
Differences between the Python and JavaScript CLIs #
The commands, options and exit codes are the same. The differences are minor:
| Python | JavaScript | |
|---|---|---|
| Executable | compense | npx compense (or compense if you install the package globally) |
--version | Doesn’t exist | Prints the SDK version |
| Per-command help | compense <command> --help | A single general help (--help or -h) |
| Option position | After the command (and after the action for clock / simulate) | Anywhere |
| Connection error or timeout | Shown by the interpreter (traceback) | error: … and code 1 |