Skip to main content
Two endpoints, one for each way a customer can pay — connecting a wallet, or sending to a pay-to address. Both take a quote and return what the customer needs.
POST /create-pool-connectReturns your pool address for the customer’s wallet to call deposit() on.
string
required
string
required
Your merchant ID — the same one you passed to create-quote. It has to match the quote’s owner, or the call returns 403.
string
The customer’s connected wallet. Optional. If you’ve enabled payer screening, the screen runs only when you send this, so send it whenever you have it.
A successful response is wrapped: { "ok": true, "intent": { … } }. Calling twice for the same quote is safe — you get the existing waiting intent back with "reused": true.
string
Intent ID (a UUID). Use it to poll payment status.
string
The contract to call. Verify this before signing.
string
A 0x-prefixed 16-byte tag. Pass it to deposit() so the payment is attributable.
string
Settlement token symbol, e.g. EURC — not a contract address. Resolve the address for chainId yourself. Chains and tokens.
number
Decimals for that token on that chain. Use this rather than assuming 6.
string
Amount in base units.
number
Accepted deviation from the expected amount, in basis points.
number
Chain to submit on — it comes from the quote. Every network live today is a test network; the examples on this page use Base Sepolia, 84532.
string
Starts at waiting.
string
When this intent lapses — one hour after it was created.
object
Verification bundle. Re-prove it client-side rather than trusting it. Why.
deposit() is a contract call, so your pool needs code on that chain. If it hasn’t been deployed yet this endpoint deploys it for you first; if that can’t be done it returns 409 with pool_not_deployed — offer the pay-to-address option instead, which works before the pool exists. You also get a 409 (pool_not_provisioned) if no payout address has been set up for your account yet.
The fee numbers in binding are the ones frozen into your pool: 75 bps to us and 25 bps to a partner on the gross. That’s it — 1% all-in, so you net 99% on the connect rail. The deposit rail’s intent.surchargeUnits above is separate: a per-payment network fee, fixed into that one-time address and capped at 10% of expectedAmount, taken at the forwarder before the funds ever reach your pool. In the example, 245000 of a 49000000 base-unit order is 0.5% — well under the cap. Fees.

Displaying a deposit address

Verify before you show it

Re-derive the forwarder from the chain-read pool address and confirm it matches. If it doesn’t, show nothing. Verification.

Show the address, amount, token, and chain

All four. Most failed payments are a customer sending the right amount of the wrong token, or the right token on the wrong chain.

Offer a QR code

Most customers pay from a phone.

Say how long the address is good for

It reduces panic when an exchange withdrawal is slow. The address is watched for seven days from creation by default, configurable down to one hour, and a transfer that lands inside that window is still credited even after expiresAt has passed.
Two limits worth designing around. A transfer that arrives after the watch window isn’t detected automatically — the funds are safe, because that address can only pay your pool, but recovering them needs us to step in. And once an order has settled, a further transfer to the same address isn’t picked up either: create a new payment for a new attempt rather than re-showing an old address. Edge cases.
Never show a deposit address you haven’t verified. It is the one screen where a compromised response could redirect a customer’s money, which is exactly why the verification exists.

Errors

These two endpoints put the machine-readable code in error, e.g. { "error": "quote_expired" } — the separate error_code field described in the error reference is present only on the compliance refusals (payment_blocked, unavailable_in_region). Branch on error here.
Full error reference.