Chromia Pay

Overview

Accept CHR in about twenty lines. Your server creates a payment, the customer pays at a URL, and a signed webhook tells you when the money is final.

Chromia Pay is a non-custodial CHR payment gateway. The customer's funds go from their wallet straight to your wallet. We hold no keys and never take custody; our job is to watch the chain and tell your server when money has arrived and is final.

Fulfil from the webhook. Never from the redirect.

A customer can close the tab the moment their wallet confirms, and anything a browser can tell your server, an attacker can tell your server too. The webhook is server-to-server, signed with a secret only you and we hold, and retried until you accept it. It is the only thing that means paid.

How a payment flows

Your server creates a payment

One API call with an amount and a success_url. You get back a checkout_url.

The customer pays

At that URL — hosted on our origin, or embedded in a frame over your own page. They can pay from a browser wallet on Chromia or BNB Smart Chain — Base is offered in sandbox only, since Base mainnet has no CHR bridge — or send manually from an exchange withdrawal or the Chromia Vault app.

We watch the chain

Chromia reaches finality in about two seconds and has no reorgs. On the EVM rails we wait for the chain's own finality policy. Either way, a payment is only confirmed once the money is irreversible.

Your server is told, and ships the order

A signed payment.confirmed (or payment.overpaid) webhook. This is the event you act on.

Before you write any code

Three things exist per environment, and a payment cannot be created without the first two. All three are set up in the dashboard.

A verified payout wallet

The address the money lands in, proven yours by signing a challenge with it. Until one exists on a rail, checkout will not offer that rail — quoting an address we cannot prove you control is how money gets lost.

An API key

cpay_sk_test_… or cpay_sk_live_…. Test keys cannot move real CHR; live keys can. Shown once, stored as a hash.

A webhook endpoint

Where confirmations arrive. Without one, payments still confirm and are still recorded — you are simply never told, so nothing ships.

Every environment — live, and each sandbox — has its own set of all three, and nothing crosses between them. A sandbox is a full isolation boundary, not a flag.

Things worth knowing early

  • Amounts are decimal strings. "12.50", never 12.5. A float cannot hold 0.1 and money is not the place to discover that. CHR has six decimals.
  • amount and amount_expected can differ. amount is what you asked for; amount_expected is what the payer is told to send. They are equal unless another open payment in the same environment already asks for that exact figure, in which case the newer one gains a few minor units of attribution dust — an EVM transfer carries no memo, so the amount is the only thing that tells two identical orders apart. Never assume they are equal, and never hard-code either.
  • Refunds are not something we can do. We hold no keys, so there is nothing here to refund from. Overpayments and underpayments come with the payer's identity so you can settle them yourself.

On this page