providercheck: the conformance kit

providercheck proves that your merchant-provider/v1 API behaves as the contract says, against your sandbox, before you go live. It runs the same lines as Chargeless's live contract check, then what a live system cannot show without moving money: a real refund and its replay, an idempotency conflict, an over-refund your API must refuse, a real cancellation, a refused key that stays refused, and every get_operation state. Going live needs a passed run from the last 30 days, uploaded in the panel.

It is one file with no dependencies. It runs on your machine, so it also reaches a sandbox on localhost or inside your VPN, and your sandbox secret never leaves it.

Download

Version providercheck/2, for contract revisions 1.0 to 1.2.

System File
macOS, Apple silicon providercheck-darwin-arm64
macOS, Intel providercheck-darwin-amd64
Linux, x86-64 providercheck-linux-amd64
Linux, ARM64 providercheck-linux-arm64
Windows, x86-64 providercheck-windows-amd64.exe

SHA256SUMS lists the SHA-256 of each file. Download from a terminal and check it before you run it:

sh
# macOS on Apple silicon; use your file's name from the table
curl -fsSLO https://chargeless.io/developers/downloads/providercheck/providercheck-darwin-arm64
curl -fsSLO https://chargeless.io/developers/downloads/providercheck/SHA256SUMS
grep providercheck-darwin-arm64 SHA256SUMS | shasum -a 256 -c -    # Linux: sha256sum -c -
mv providercheck-darwin-arm64 providercheck && chmod +x providercheck
./providercheck -version

On Windows, check the file with Get-FileHash providercheck-windows-amd64.exe in PowerShell and compare it with the line in SHA256SUMS.

The files are not signed with an Apple or Microsoft certificate. A file downloaded with curl runs as it is; one downloaded with a browser on macOS is quarantined, and xattr -d com.apple.quarantine providercheck releases it after you checked its SHA-256.

Before you run it

  1. Your API runs in front of your billing system's sandbox, where a refund and a cancellation cost nothing.
  2. The sandbox verifies the sandbox signing secret. Chargeless shows it once, starting srmps_, when you first save your connection in the panel (Settings → Integrations → your connection). To get a new one, edit the connection and tick "Issue a new sandbox signing secret". Configure it on the sandbox only: your production API must refuse it.
  3. Pick fresh fixtures in the sandbox: a customer, a refundable charge of that customer and, if you support cancellations, an active subscription of that customer. The run refunds the charge (one minor unit with partial refunds, otherwise the whole remainder) and cancels the subscription, so use new ones for every run.
  4. Your workspace id, shown as Workspace ID under Settings → General, and filled in for you in the command the panel shows under Conformance kit. Chargeless's idempotency keys start with it, so the kit sends them the same way.

Run it

Secrets come only from the environment, never from the command line.

sh
export PROVIDERCHECK_SANDBOX_SIGNING_SECRET=srmps_…
# optional, when your sandbox needs them:
#   export PROVIDERCHECK_BEARER_TOKEN=…
#   export PROVIDERCHECK_EDGE_HEADERS='[{"name":"CF-Access-Client-Id","value":"…"}]'   (at most 3)

./providercheck -sandbox \
  -base-url https://sandbox.billing.example.com/supportroute \
  -tenant <your workspace id> \
  -customer cus_… -transaction ch_… -subscription sub_… \
  -out providercheck-report.json

For the MCP binding, add -transport mcp and use your sandbox's MCP endpoint as -base-url.

Flag Use
-sandbox Required: you confirm the target is a sandbox, because the run refunds and cancels for real
-base-url Your sandbox's base URL, or its MCP endpoint with -transport mcp
-transport rest (the default) or mcp
-tenant Your workspace id
-customer, -transaction, -subscription The fixtures; leave out -subscription if you do not support cancellations
-out Where the sealed report goes (default providercheck-report.json)
-allow-private A sandbox over plain http, on another port or at a private address (localhost, a VPN)
-client-cert, -client-key Your own test client certificate, for a sandbox that requires mTLS
-settle-timeout How long to wait for a pending outcome: default 2 min, at most 30 min
-v Log every call (ids, statuses and latencies, never a body)
-version Print the kit's version and exit

The kit refuses to start with a production secret (srmp_…), without -sandbox, or with a fixture reference the contract would refuse (a run of 13 or more digits, for example). It also refuses an origin the report could not record, such as an IPv4 address whose digits and port join into 13 or more digits: use a host name instead.

Read the result

It prints one line per check and a verdict, and the WARN lines before them are the calls the kit provoked on purpose (a wrong signature, a conflict):

text
providercheck/2 against https://sandbox.billing.example.com over rest (run 01a1cec2-cdc0-7251-af9e-9fc989823775, contract 1.0)
  reachability             passed  TLS and an HTTP answer from the configured endpoint, through Chargeless's egress
  describe                 passed  contract version 1.0; a wrong signature and a stale timestamp were refused
  get_transaction          failed  schema_invalid get_transaction answered 200 with a body that breaks the contract (schema_invalid): `amount.amount_minor` is missing
                                   X-SR-Request-Id 01a1cec2-cdc8-79eb-b918-1b84d0bab31f
  …
FAILED; sealed report written to providercheck-report.json
  • Exit status 0 means every check passed, 1 that one failed, 2 that the run could not start.
  • A failing line names its check, a code, what was expected and, for an answer that breaks the schema, the field. The X-SR-Request-Id finds the call in your logs.
  • The REST binding by example shows the answer each check expects, and Proving it lists every check with what makes it pass.
Sandbox check Passes when
refund_over_refundable A real refund one minor unit over the remainder is refused with amount_exceeds_refundable
refused_key_final That key replays refused, get_operation says failed, and no money moved
refund_executes The refund executes once and refunds[] lists it under Chargeless's key
refund_replay The replay returns the original result and refunds nothing more
refund_conflict The key with another amount gets 409 idempotency_conflict, and nothing runs
cancel_executes, cancel_replay, cancel_conflict The same for an immediate cancellation
cancel_refused_key A second cancellation is refused with already_canceled, replays refused and reads failed
one_effect_per_call The refund leaves the subscription alone, and the cancellation leaves the charge alone
operation_states Every key read again keeps its final state, and a key never sent is unknown

Upload the report

The report file is sealed with a key derived from your sandbox secret, so you can tell later that it is the kit's unmodified output. Upload it in the panel under Settings → Integrations → your connection → Conformance kit: choose the file, tick "This file is the kit's unmodified output for this workspace" and attest it.

  • Going live needs a passed report for your transport (REST or MCP) from the last 30 days, and so does a later change of transport.
  • Chargeless records the file's SHA-256 (shasum -a 256 providercheck-report.json), the kit version, the run, the transport, your sandbox's origin and each line's result. It does not keep the file, so keep your copy.
  • Chargeless cannot verify the seal (it does not keep your sandbox secret): the attestation is your member's statement that the file is the kit's output.

Try it on your machine first

Before your sandbox is ready, run the kit against the complete server on The REST binding by example, as Connect your billing system in an afternoon shows. It passes every line, so you see what a passing run looks like.