Get provider keys
This page tells you how to get the keys and settings that each adapter needs. For each provider, it gives:
- the access type,
- where to sign up, and the path to the keys in the dashboard,
- which values to copy, the adapter option for each value, and a suggested environment variable,
- how to change from sandbox to production,
- the webhook setup,
- the gotchas.
The facts on this page come from setting up the accounts on 9 Oct 2026. Dashboards change. When this page says "check in the dashboard", we did not confirm that detail.
You do not need any key to start. The mock adapter moves no money and needs no account. Add real providers one at a time.
Summary
The times are estimates for the first sandbox key. Production access can take longer.
| Adapter | Access type | Keys needed | Time to get started |
|---|---|---|---|
| Relay | Self-serve | API key | About 5 minutes |
| LI.FI | Self-serve | API key, integrator string | About 5 minutes |
| MoonPay | Self-serve sandbox; review (KYB) for live | Publishable key, secret key, webhook key | About 10 minutes |
| Transak | Self-serve sandbox; business profile for live | API key, API secret, referrer domain | About 10 minutes |
| Xendit | Self-serve test mode | Secret key, webhook verification token | About 10 minutes |
| Onramper | Self-serve sandbox after an onboarding form; paid plan and KYB for live | API key, Ed25519 signing key, webhook secret | About 15 minutes |
| Coinbase | Self-serve limited test access; application for full access | CDP Secret API key (id and secret), webhook secret | About 15 minutes |
| Stripe | Application and review | Secret key, publishable key, webhook signing secret | Days (Stripe reviews the application) |
| Stripe Link | Private preview; Stripe onboards the account | Secret key, publishable key, Link OAuth client id, webhook signing secret, optional token key | Days to weeks (Stripe onboarding) |
| Swapped | Application (business onboarding) | Public key, secret key | Days |
| Banxa | Partner onboarding (sandbox first; production after Banxa approves the integration) | Partner reference, v2 API key, HMAC key pair | Days |
| PayTrie | Email support@paytrie.com for a developer API key; no documented sandbox | API key, webhook signing secret, optional token key | Days (estimate; PayTrie answers email within 24 hours) |
| Flashnet | Self-serve dashboard; Flashnet reviews the account before the API works; no sandbox | Server key (fn_), webhook secret | Days (account review) |
| Meld | Sales (contact form) | API key, webhook secret | Days to weeks |
| Bridge | Sales | API key, webhook public key | Days to weeks |
| Binance | Partner approval; no sandbox | API URL, client id, access token, RSA key pair, Binance public key | Weeks |
| Peer | Not recommended for production | API key, webhook secret | Not recommended |
| Reown (WalletConnect) | Self-serve | Project id (public) | About 5 minutes |
Before you start
The webhook URL
The server receives provider webhooks at one route per adapter:
POST {baseUrl}/webhooks/{adapterId}baseUrl is the baseUrl that you give to createOpenRamp. adapterId is the id of the adapter, for example moonpay. Example: https://app.example.com/api/openramp/webhooks/moonpay. The adapter verifies each webhook with the secret or public key that you copy from the provider.
A provider cannot send a webhook to localhost. To test webhooks on your computer, use a tunnel to a public HTTPS URL. Set baseUrl to that URL.
Sandbox and production
Every adapter takes the same option: env: 'sandbox' | 'production'. For Stripe and Xendit, the key prefix gives the default. Binance, LI.FI and Relay have no sandbox switch: their env comes from the host. The sections below give the details for each adapter. Each adapter shows its environment as the read-only adapter.env.
Also set livemode: true on createOpenRamp in production. Events then carry livemode. The server checks each adapter.env against livemode when it starts:
livemode | Adapter env | Result |
|---|---|---|
true | sandbox | The server does not start. A test payment must never complete a live session. |
false | production | One warning: test sessions call a provider that moves real money. |
| Any | not set (Coinbase without env) | No check. The adapter follows each session's livemode. |
The mock adapter is sandbox, so a server with livemode: true does not start with it.
Old options still work, with a one-time deprecation warning: env: 'staging' (Transak) is env: 'sandbox', env: 'live' (Peer) is env: 'production', and sandbox: true or false (Coinbase) is env: 'sandbox' or 'production'.
Sandboxes do not have all the assets and methods of production. Known limits (Checked on 9 Oct 2026.):
| Provider | Sandbox limit |
|---|---|
| MoonPay | Test mode has USDC only as usdc on Ethereum. No usdc_base, usdc_arbitrum, usdc_optimism or usdc_polygon. |
| Relay | The testnets host knows ETH on Base Sepolia and Sepolia, but not USDC on Base Sepolia. |
| Transak | Staging has 26 fiat currencies and no INR. You cannot test UPI on staging. |
| Onramper | Staging for the US shows card only. |
| LI.FI | No sandbox host (staging.li.quest returns 403). Test with small quotes on mainnet, and never send. |
Keep keys safe
- Keep secret keys on the server only. Never put a secret key in a
NEXT_PUBLIC_variable or in your client bundle. - Put keys in an env file that git ignores. The repo ignores
.env,.env.localand.dev.vars. In production, use your platform's secrets (for examplewrangler secret putor the Vercel environment variables). - Never paste keys into a chat, an issue, a pull request or a log.
- If a key was exposed, rotate it in the provider dashboard at once. Then update your env file and your platform secrets.
- Use a different key for each environment (local, staging, production). Then you can rotate one key and the other environments continue to work.
- The examples on this page show no real key values. The prefixes (for example
pk_test_) only help you find the correct key.
Relay
Access type: self-serve.
Sign up: dashboard.relay.link.
Get the key:
- Create an organization.
- Open API keys. Click Create an API Key.
- Give the key a name, for example
staging. Copy the key.
| Value | Adapter option | Env var |
|---|---|---|
| API key | apiKey | RELAY_API_KEY |
relay({ apiKey: process.env.RELAY_API_KEY })The adapter sends the key in the x-api-key header.
Sandbox and production: the default API is https://api.relay.link (mainnets). For testnets, set baseUrl: 'https://api.testnets.relay.link'. The adapter env is then sandbox; else it is production. Make one key for each environment. Check in the dashboard if a testnet key is different from a mainnet key.
Sandbox limits: The testnets host (https://api.testnets.relay.link) knows ETH on Base Sepolia and on Sepolia. It does not know USDC on Base Sepolia. To test on testnets, quote ETH, not USDC. Checked on 9 Oct 2026.
Webhooks: the Relay adapter has no webhook handler. Status comes from polling. You can configure webhooks per key in the Relay dashboard, but the adapter does not use them.
Gotchas:
- Relay requires an API key for quotes (
POST /quote/v2) under its announced policy from 2 Oct 2026. Some requests without a key may still work today, but Relay can refuse them at any time. Always setRELAY_API_KEY. A refused quote gets401 UNAUTHORIZED_QUOTE. A quote that setsreferrerwithout a key is refused now. - Without a key, status checks use
/requests/v2. Relay retires it on 24 Nov 2026.
LI.FI
Access type: self-serve.
Sign up: portal.li.fi.
Get the key:
- Open Integrations. Click New integration.
- Give it a name.
- Set the integration string. It is lowercase and you cannot change it later. This is the adapter's
integrator. - Optional: add fee wallets. Skip this step if you charge no fee.
- Click Create API key. Copy the key at once. LI.FI shows it one time only.
| Value | Adapter option | Env var |
|---|---|---|
| API key | apiKey | LIFI_API_KEY |
| Integration string | integrator | LIFI_INTEGRATOR |
lifi({ apiKey: process.env.LIFI_API_KEY, integrator: process.env.LIFI_INTEGRATOR })The adapter sends the key in the x-lifi-api-key header.
Sandbox and production: the adapter has no sandbox switch, and its env is always production. The API is https://li.quest/v1 (baseUrl). Quotes move no money. A wallet transaction moves real funds, so test with small amounts.
Sandbox limits: LI.FI has no sandbox host: staging.li.quest returns 403. Test with small quotes on the mainnet host only. Quotes move no money. Never send the transaction in a test. Checked on 9 Oct 2026.
Webhooks: the LI.FI adapter has no webhook handler. Status comes from polling.
Gotchas:
- With a key, the quote limit is about 12,000 requests in 2 hours. Without a key, it is 75 requests in 2 hours. The server quotes on each amount change, so you reach the keyless limit fast.
- A fee (
feeBps) needsintegratorand a fee wallet for that integration. Without a fee wallet, LI.FI refuses the quote (error code1011). - If you lose the key, make a new one. You cannot see it again.
MoonPay
Access type: self-serve sandbox (Test mode). Live access needs a review (KYB).
Sign up: dashboard.moonpay.com. A new account starts in Test mode.
Get the keys: open Developers, then API Keys. The page shows four keys:
| Value | Prefix in Test mode | Adapter option | Env var |
|---|---|---|---|
| Publishable Key | pk_test_ | publishableKey | MOONPAY_PUBLISHABLE_KEY |
| Secret Key | sk_test_ | secretKey | MOONPAY_SECRET_KEY |
| Webhook Key | wk_test_ | webhookKey | MOONPAY_WEBHOOK_KEY |
| Public Key | not used |
moonpay({
publishableKey: process.env.MOONPAY_PUBLISHABLE_KEY!,
secretKey: process.env.MOONPAY_SECRET_KEY!,
webhookKey: process.env.MOONPAY_WEBHOOK_KEY,
env: 'sandbox',
})Sandbox and production: set env: 'sandbox' with the _test_ keys. Set env: 'production' with the live keys. env is required. To go live, click Start review in the dashboard and complete KYB.
Sandbox limits: MoonPay test mode has USDC only as usdc (USDC on Ethereum). usdc_base, usdc_arbitrum, usdc_optimism and usdc_polygon are not in test mode. To test in test mode, quote USDC on Ethereum. A test mode quote for USDC on another chain fails. Base is first in the default deliverAssets, so set the destination to USDC on Ethereum for test mode. Checked on 9 Oct 2026.
Webhooks: register {baseUrl}/webhooks/moonpay in the dashboard (check in the dashboard for the exact page). Copy the Webhook Key to webhookKey. Without webhookKey, the adapter rejects every webhook.
Gotchas:
- The "refresh" icon next to each key rotates that key. The old key stops at once. Do not click it unless you want a new key.
- Test mode does not support every currency. For example,
usdc_basereturned "Currency not supported in test mode". UsedeliverAssetsto pick an asset that Test mode supports. envmust agree with the keys. A live key withenv: 'sandbox'(or the reverse) does not work.
Transak
Access type: self-serve sandbox (Staging). Live access needs a business profile.
Sign up: dashboard.transak.com.
Get the keys:
- At the top of the dashboard, change the environment selector from Production to Staging.
- Open Developers. Copy the API Key.
- Click Generate to make the API Secret. Copy it.
- Register your web domain as the referrer domain (check in the dashboard for the exact page).
| Value | Adapter option | Env var |
|---|---|---|
| API Key | apiKey | TRANSAK_API_KEY |
| API Secret | apiSecret | TRANSAK_API_SECRET |
Your domain, for example app.example.com | referrerDomain | TRANSAK_REFERRER_DOMAIN |
transak({
apiKey: process.env.TRANSAK_API_KEY!,
apiSecret: process.env.TRANSAK_API_SECRET!,
referrerDomain: process.env.TRANSAK_REFERRER_DOMAIN!,
env: 'sandbox',
})The adapter uses the secret to get an access token: POST https://api-stg.transak.com/partners/api/v2/refresh-token with the header api-secret and the body { apiKey }. It does this for you.
Sandbox and production: set env: 'sandbox' with Staging keys. The adapter then uses the Transak staging hosts. The default is 'production'. The old value 'staging' still works, with a deprecation warning. To go live, click Complete your business profile in the dashboard. Then copy the Production keys.
Sandbox limits: Transak staging has 26 fiat currencies. INR is not one of them, so you cannot test UPI on staging. Checked on 9 Oct 2026.
Webhooks: register {baseUrl}/webhooks/transak in the Transak dashboard (check in the dashboard for the exact page). There is no separate webhook secret: Transak signs webhooks with the access token, and the adapter keeps that token.
Gotchas:
- If you forget
env: 'sandbox', the adapter sends Staging keys to the production API, and every call fails. - Partners must make widget URLs on the server (Secure Widget URL). The adapter does this in
start(). - A new access token cancels the old token. Do not share one API key between two deployments (for example your computer and staging). Each deployment refreshes the token and stops the other one.
- The adapter verifies a webhook with the cached access token. Before webhooks arrive, run at least one quote or start on the instance, or use a shared store.
Xendit
Access type: self-serve test mode.
Sign up: dashboard.xendit.co. Use Test mode.
Get the keys:
- Open Settings, then Developers, then API keys.
- Click Generate secret key. In Test mode, the key starts with
xnd_development_. - Set the permissions. The adapter calls the Payments API v3 (
POST /v3/payment_requestsandGET /v3/payment_requests/{id}). Give the key write permission for the money-in (payment request) products. Check in the dashboard for the exact permission names. - Open Settings, then Webhooks. Copy the Webhook verification token.
- Activate each payment channel that you offer (for example QRIS, QR Ph, PayNow QR, DANA). Do this in Test mode first, and again in live mode. Check in the dashboard for the exact page name. A channel that is not active fails with
403 INVALID_MERCHANT_SETTINGS.
| Value | Adapter option | Env var |
|---|---|---|
| Secret key | secretKey | XENDIT_SECRET_KEY |
| Webhook verification token | webhookToken | XENDIT_WEBHOOK_TOKEN |
xendit({ secretKey: process.env.XENDIT_SECRET_KEY!, webhookToken: process.env.XENDIT_WEBHOOK_TOKEN! })Sandbox and production: the key prefix sets the mode. xnd_development_ keys use test mode (env is sandbox). xnd_production_ keys move real money (env is production). You can also set env. A value that does not agree with the key throws when you build the adapter. The API URL is the same (apiUrl, default https://api.xendit.co). Copy the webhook token of the same mode as the key (check in the dashboard).
Webhooks: in Settings, then Webhooks, set the payment webhook URL to {baseUrl}/webhooks/xendit. The adapter compares the x-callback-token header with webhookToken.
Gotchas:
- A key with no read permission on balance gets
403onGET /balance. The adapter does not call/balance, so this is not a problem. - The webhook token has no signature or timestamp. Keep it as secret as the API key.
- Xendit has no crypto. Use the adapter with a merchant destination.
- Activate each payment channel before you use it. Do this in test mode and again in live mode. A channel that is not active gets
403 INVALID_MERCHANT_SETTINGS"payment channel has not been activated". On 2026-10-09, a new test mode account got this error for QRIS and QR Ph, while DANA worked. The adapter shows the user "This payment method is not set up for this app yet" and writes an error log that names the channel. See Xendit errors. - PayNow QR uses the channel code
SGQR. The old codePAYNOWgets400 API_VALIDATION_ERROR"API endpoint and method is not supported for 'PAYNOW' channel code with country 'SG'".
Onramper
Access type: self-serve sandbox after an onboarding form. Live access needs a paid subscription and KYB.
Sign up: dashboard.onramper.com/users/sign_up. Then complete the onboarding form: entity, project, industry, country, expected volume and go-live date.
Get the keys:
- After the form, the dashboard shows a Staging API Key (
pk_test_...). Copy it. - Find the signing key and the webhook secret in the dashboard settings. Check in the dashboard for the exact page.
The adapter option secretKey is an Ed25519 private key for "Signature V2". It accepts a PKCS#8 PEM, base64 PKCS#8 DER, or a 32-byte seed (base64 or hex). If you make the key pair yourself, give Onramper the public key:
openssl genpkey -algorithm ed25519 -out onramper-private.pem # secretKey
openssl pkey -in onramper-private.pem -pubout -out onramper-public.pem # give to OnramperCheck in the dashboard if Onramper makes the key for you, or if you upload your public key.
| Value | Adapter option | Env var |
|---|---|---|
API key (pk_test_... or pk_prod_...) | apiKey | ONRAMPER_API_KEY |
| Ed25519 private key | secretKey | ONRAMPER_SIGNING_KEY |
| Webhook secret | webhookSecret | ONRAMPER_WEBHOOK_SECRET |
onramper({
apiKey: process.env.ONRAMPER_API_KEY!,
secretKey: process.env.ONRAMPER_SIGNING_KEY!,
webhookSecret: process.env.ONRAMPER_WEBHOOK_SECRET,
env: 'sandbox',
})Sandbox and production: set env: 'sandbox' with the pk_test_ key (API https://api-stg.onramper.com). Set env: 'production' with the pk_prod_ key. env is required.
Sandbox limits: Onramper staging for the US shows card only. You cannot test other US methods (for example ACH or PayPal) on staging. Checked on 9 Oct 2026.
Webhooks: send {baseUrl}/webhooks/onramper to Onramper (in the dashboard or through your Onramper contact; check in the dashboard). Copy the webhook secret to webhookSecret.
Gotchas:
- Without
webhookSecret, the adapter cannot learn the transaction id, and status stays "still paying". - The checkout is bound to the user's IP. Without a client IP header, start fails.
- Register the public key before the first start. Without it, start gets
401{"errorId":4011,"message":"No V2 signing key is registered for this API key..."}. The Onramper key setup page says to send the public key (PEM) to your Onramper account manager or support. Use one key pair for staging and another for production. The adapter logs this as a setup error and does not retry. - Onramper also wants the server egress IPs and your domains on its allowlist. A server call from another IP gets
403. - The adapter does not accept a PEM with
\nescapes. A PEM with real new lines works. For a one-line env var, use the base64 DER form:openssl pkey -in onramper-private.pem -outform DER | base64.
Coinbase
Access type: self-serve limited test access. Full access needs an application.
Sign up: sign in at portal.cdp.coinbase.com. Pick a project.
Get the keys:
- Open Payments, then Onramp & Offramp.
- In Configuration, set the Application display name. Add your domain to the Domain allowlist. The
redirectUrlmust be on this list. - Open API keys. Create a Secret API key. Copy the key id and the secret at once. The portal shows the secret one time only.
- Create the Onramp webhook subscription and copy its secret (check in the portal for the exact page).
- For full access, click Apply for access.
| Value | Adapter option | Env var |
|---|---|---|
Secret API key id (the key name or id) | apiKeyId | CDP_API_KEY_ID |
| Secret API key secret (base64 Ed25519 or EC PEM) | apiKeySecret | CDP_API_KEY_SECRET |
| Onramp webhook secret | webhookSecret | CDP_WEBHOOK_SECRET |
| Project id (optional, not used by the session API) | appId | CDP_PROJECT_ID |
coinbase({
apiKeyId: process.env.CDP_API_KEY_ID!,
apiKeySecret: process.env.CDP_API_KEY_SECRET!,
webhookSecret: process.env.CDP_WEBHOOK_SECRET,
})Sandbox and production: set env: 'sandbox' or env: 'production'. Without env, each session's livemode decides: with livemode: true on createOpenRamp, the adapter leaves sandbox mode. The old sandbox option still works, with a deprecation warning. A new project has limited test access: 25 test transactions, at most 5 USD each.
Webhooks: subscribe to onramp.transaction.created, onramp.transaction.updated, onramp.transaction.success and onramp.transaction.failed with the URL {baseUrl}/webhooks/coinbase. Copy the subscription secret to webhookSecret. Without it, the adapter rejects every webhook.
Gotchas:
- Guest Apple Pay (
guestCheckout, the headless flow) needs extra approval from Coinbase. Itsdomainmust be on the domain allowlist. - The hosted legs need a Coinbase account for each user.
- Copy the secret when you create the key. If you lose it, make a new key.
Stripe
Access type: application and review.
Sign up: in the Stripe dashboard, open Crypto onramp, then Get started.
Apply:
- Update the domains where the onramp runs.
- Click Submit your Stripe application. Give your business details, a business description, the answer to the Terms of Service question (yes or no), and whether you fill in the wallet address for the user.
- Wait for approval. Check in the dashboard if the onramp works in test mode before approval.
Get the keys: the adapter uses the API keys of your Stripe account. Open Developers, then API keys (check in the dashboard). A restricted key with onramp access also works.
| Value | Adapter option | Env var |
|---|---|---|
Secret key (sk_test_... in test mode) | secretKey | STRIPE_SECRET_KEY |
Publishable key (pk_test_... in test mode) | publishableKey | STRIPE_PUBLISHABLE_KEY |
Webhook signing secret (whsec_...) | webhookSecret | STRIPE_WEBHOOK_SECRET |
stripe({
secretKey: process.env.STRIPE_SECRET_KEY!,
publishableKey: process.env.STRIPE_PUBLISHABLE_KEY!,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
})Sandbox and production: the key prefix sets the mode. sk_test_ and pk_test_ keys use test mode. Live keys start with sk_live_ and pk_live_. The adapter reads env from the key prefix (sk_test_ or rk_test_ is sandbox). You can also set env. A value that does not agree with the key throws when you build the adapter.
Webhooks: open Developers, then Webhooks. Add an endpoint with the URL {baseUrl}/webhooks/stripe and the event crypto.onramp_session.updated. Copy its signing secret to webhookSecret. Test mode and live mode have different endpoints and secrets.
Gotchas:
- The publishable key goes to the browser for the embedded onramp. That is safe. The secret key must stay on the server.
- Set
providerRenderers: { stripe: stripeOnrampRenderer() }on the modal, orsurface: 'redirect'on the adapter. See Stripe.
Stripe Link
Access type: private preview. No call works, also in a sandbox, until Stripe finishes your onboarding.
Sign up: submit the crypto onramp application. Then work with your Stripe contact to:
- Turn on the feature gates for the Embedded Components onramp APIs and the Link OAuth APIs.
- Turn on Link as a payment method in Settings, then Payment methods.
- Get the Link OAuth client id. Stripe provisions it.
Where to find the keys: the secret key and the publishable key are on the API keys page. Stripe gives you the OAuth client id. The adapter does not need the OAuth client secret: it never refreshes a token.
Env var names:
stripeLink({
secretKey: process.env.STRIPE_SECRET_KEY!,
publishableKey: process.env.STRIPE_PUBLISHABLE_KEY!,
oauthClientId: process.env.STRIPE_LINK_OAUTH_CLIENT_ID!,
webhookSecret: process.env.STRIPE_LINK_WEBHOOK_SECRET!,
tokenKey: process.env.STRIPE_LINK_TOKEN_KEY, // optional, at least 32 characters
})Webhooks: add an endpoint with the URL {baseUrl}/webhooks/stripe-link and the event crypto.onramp_session.updated. Copy its signing secret to webhookSecret.
Gotchas:
- Test with the sandbox values in Stripe's guide: OTP
000000, SSN000000000, card4242 4242 4242 4242, and 100 USD or less. - See Stripe Link for the client part.
Swapped
Access type: application (business onboarding). We saw no self-serve sandbox.
Sign up: apply through Swapped business onboarding (see docs.swapped.com). Swapped gives you the keys after onboarding. Check in the dashboard for the path.
| Value | Adapter option | Env var |
|---|---|---|
Public key (pk_...) | publicKey | SWAPPED_PUBLIC_KEY |
Secret key (sk_...) | secretKey | SWAPPED_SECRET_KEY |
swapped({
publicKey: process.env.SWAPPED_PUBLIC_KEY!,
secretKey: process.env.SWAPPED_SECRET_KEY!,
env: 'sandbox',
})Sandbox and production: set env: 'sandbox' for https://sandbox.swapped.com. The default is 'production'. The sandbox has BTC and ETH testnets and test cards only.
Webhooks: you do not register a URL. The adapter puts {baseUrl}/webhooks/swapped in each widget URL as responseUrl. The adapter verifies notifications with secretKey.
Gotchas:
- An empty
secretKeymakes the adapter refuse every notification.
Banxa
Access type: partner onboarding. Banxa issues sandbox credentials first. Production credentials come separately, after Banxa approves the integration. Banxa has no self-serve sign-up and no OAuth.
Get the keys: in the Banxa Partner Dashboard (per environment, switch with the toggle at the top):
| Value | Adapter option | Env var |
|---|---|---|
| Partner reference (the first segment of every API path) | partnerRef | BANXA_PARTNER_REF |
v2 API key (x-api-key) | apiKey | BANXA_API_KEY |
| HMAC API key | hmacKey | BANXA_HMAC_KEY |
| HMAC secret | hmacSecret | BANXA_HMAC_SECRET |
banxa({
partnerRef: process.env.BANXA_PARTNER_REF!,
apiKey: process.env.BANXA_API_KEY!,
hmacKey: process.env.BANXA_HMAC_KEY,
hmacSecret: process.env.BANXA_HMAC_SECRET,
env: 'sandbox',
})Sandbox and production: set env: 'sandbox' for https://api.banxa-sandbox.com with the sandbox keys, or env: 'production' for https://api.banxa.com. env is required. Sandbox keys work only on the sandbox host, and production keys only on the production host: the wrong pair gives 401.
Webhooks: set the webhook URL for each environment in the Partner Dashboard to {baseUrl}/webhooks/banxa. Banxa signs webhooks with the HMAC key pair, not with the v2 API key. With more than one active HMAC pair, Banxa signs with the oldest pair that is not revoked; the dashboard Webhooks page shows which one. Use Send test to check the URL.
Gotchas:
- The signature covers the path of your webhook URL. If a proxy rewrites the path, set
webhookPathto the path that Banxa calls. - If the dashboard shows only a v2 API key, ask your Banxa account manager for the HMAC key pair.
- Sandbox allows 120 requests per minute per merchant. Prefer webhooks over polling.
- Before go-live, Banxa requires a disclaimer that Banxa processes the payment as merchant of record (required disclaimer).
PayTrie
Access type: request by email. Register a PayTrie account at app.paytrie.com/SignupEmail, then email support@paytrie.com with your registered email, your use case and your expected volume, and ask for a developer API key (Using the Platform API).
Get the keys:
| Value | Where | Adapter option | Env var |
|---|---|---|---|
Developer API key (x-api-key) | From PayTrie support | apiKey | PAYTRIE_API_KEY |
Webhook signing secret (whsec_...) | The answer to the first PUT /v2/webhook-configurations (below) | webhookSecret | PAYTRIE_WEBHOOK_SECRET |
| Token key (32 characters or more, optional) | You make it, for example openssl rand -base64 32 | tokenKey | PAYTRIE_TOKEN_KEY |
paytrie({
apiKey: process.env.PAYTRIE_API_KEY!,
webhookSecret: process.env.PAYTRIE_WEBHOOK_SECRET,
tokenKey: process.env.PAYTRIE_TOKEN_KEY,
})Sandbox and production: PayTrie documents only https://api.paytrie.com. The adapter defaults to env: 'production'. Ask PayTrie support for a test host; to use one, set env: 'sandbox' and apiUrl.
Webhooks: register your URL once with the API. The first call returns the signing secret, and only the first call:
curl -X PUT "https://api.paytrie.com/v2/webhook-configurations" \
-H "x-api-key: $PAYTRIE_API_KEY" -H "Content-Type: application/json" \
-d '{ "url": "https://your-app.example/api/openramp/webhooks/paytrie" }'To get a new secret later, call POST /v2/webhook-configurations/signing-secret/rotate. To send a test event, call POST /v2/webhook-configurations/test.
Gotchas:
- PayTrie sends each webhook once and does not retry. The adapter also polls with the user's access token (1 hour). After that, only the webhook reports the result.
- One webhook URL per integration: use one OpenRampKit server per API key.
- The adapter never stores KYC data. Users sign up and do KYC on PayTrie pages.
- If you had v1 webhooks, turn them off after v2 works (
PATCH /webhookswith every flagfalse).
Flashnet
Access type: self-serve dashboard with an account review. Create the keys in the Orchestra dashboard. Flashnet reviews new accounts before it enables the API: until then, calls answer 403 (account_pending_approval). There is no sandbox.
| Value | Adapter option | Env var |
|---|---|---|
Server key (fn_...; not a client key fnp_...) | apiKey | FLASHNET_API_KEY |
| Webhook signing secret | webhookSecret | FLASHNET_WEBHOOK_SECRET |
| Your Tron address for refunds (needed for Tron deposits) | refundAddresses.tron | FLASHNET_TRON_REFUND |
flashnet({
apiKey: process.env.FLASHNET_API_KEY!,
webhookSecret: process.env.FLASHNET_WEBHOOK_SECRET,
refundAddresses: { tron: process.env.FLASHNET_TRON_REFUND },
})Webhooks: register the URL with the server key. The answer has the signing secret, and Flashnet shows it only once:
curl -X POST https://orchestration.flashnet.xyz/v1/webhooks \
-H "Authorization: Bearer $FLASHNET_API_KEY" \
-H "X-Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"url":"https://your.app/api/openramp/webhooks/flashnet"}'Gotchas:
- No sandbox: test with a small real order (the USD minimum is 1.00).
order.recovery_requiredevents need a separate subscription (POST /v1/webhooks/recovery). Without it, the adapter still learns the result from status checks.- Orchestra has rate limits (for example 60 requests per minute per IP for routes and limits, and 120 for estimates). Prefer webhooks over polling.
Meld
Access type: sales. We saw no self-serve sandbox: the sign-up sent us to a "Sandbox access" contact form.
Sign up: fill in the contact form on meld.io. Meld gives you a dashboard after the call. Check in the dashboard for the path to the API key.
| Value | Adapter option | Env var |
|---|---|---|
| API key | apiKey | MELD_API_KEY |
| Webhook profile secret | webhookSecret | MELD_WEBHOOK_SECRET |
meld({
apiKey: process.env.MELD_API_KEY!,
env: 'sandbox',
webhookSecret: process.env.MELD_WEBHOOK_SECRET,
})Sandbox and production: set env: 'sandbox' for https://api-sb.meld.io, or env: 'production'. env is required.
Webhooks: create a webhook profile with the URL {baseUrl}/webhooks/meld. Copy its secret to webhookSecret.
Gotchas:
- The signature covers the webhook URL. If a proxy rewrites the URL, set
webhookUrlto the URL in the Meld profile.
Bridge
Access type: sales. Production needs KYB of your company.
Sign up: contact Bridge sales. For a sandbox key, write to support@bridge.xyz. Then make a sandbox key in the dashboard with the Sandbox toggle on. Only dashboard admins can make keys.
| Value | Adapter option | Env var |
|---|---|---|
API key (sk-test-... in the sandbox) | apiKey | BRIDGE_API_KEY |
| Webhook endpoint public key (PEM) | webhookPublicKey | BRIDGE_WEBHOOK_PUBLIC_KEY |
bridge({
apiKey: process.env.BRIDGE_API_KEY!,
webhookPublicKey: process.env.BRIDGE_WEBHOOK_PUBLIC_KEY!,
env: 'sandbox',
})Sandbox and production: set env: 'sandbox' for https://api.sandbox.bridge.xyz. The default is 'production'. In the sandbox, KYC links do not work, no money moves, and Bridge sends no payment webhooks.
Webhooks: Bridge signs webhooks with an RSA key, one key for each endpoint.
- Create the endpoint with
POST /v0/webhooksand the URL{baseUrl}/webhooks/bridge. - Copy the
public_keyfrom the answer towebhookPublicKey. - Turn the endpoint on with
PUT /v0/webhooks/{id}andstatus: 'active'. A new endpoint is disabled.
See Bridge webhooks.
Gotchas:
- A new webhook endpoint has a new public key. Update
webhookPublicKeywhen you make a new endpoint.
Binance
Access type: partner approval. There is no sandbox.
Sign up: contact the Binance Pay Onchain team. See Binance access requirements.
You send to Binance:
- your RSA public key (make the key pair with OpenSSL; see the adapter page),
- the IP addresses of your server,
- your webhook URL:
{baseUrl}/webhooks/binance, - the domains of your redirect URLs,
- a logo (80 x 80 pixel PNG).
Binance gives you:
| Value | Adapter option | Env var |
|---|---|---|
| API base URL | apiUrl | BINANCE_API_URL |
| Client id | clientId | BINANCE_CLIENT_ID |
| Access token | accessToken | BINANCE_ACCESS_TOKEN |
| Webhook public key | binancePublicKey | BINANCE_WEBHOOK_PUBLIC_KEY |
| Partner code | webhookPartnerCode (optional) | BINANCE_PARTNER_CODE |
| Your RSA private key (you keep it) | privateKey | BINANCE_PRIVATE_KEY |
binance({
apiUrl: process.env.BINANCE_API_URL!,
clientId: process.env.BINANCE_CLIENT_ID!,
accessToken: process.env.BINANCE_ACCESS_TOKEN!,
privateKey: process.env.BINANCE_PRIVATE_KEY!,
binancePublicKey: process.env.BINANCE_WEBHOOK_PUBLIC_KEY!,
})Sandbox and production: there is no sandbox. Each call goes to the live API, and the adapter env is always production.
Webhooks: you give Binance the webhook URL during onboarding. The adapter verifies webhooks with binancePublicKey.
Gotchas:
- Binance allows calls only from the server IPs that you sent. A platform with changing IPs needs a fixed outbound IP.
- The adapter was not tested against the live API. Read the TO VERIFY notes on the Binance page.
Peer
Access type: not recommended for production. Peer is a peer-to-peer marketplace. It has legal risk, and paying strangers for crypto may breach the payment apps' terms. The adapter is off by default: the factory throws unless you pass enabled: true.
Sign up: see docs.pay.peer.xyz. The merchant API key is in Settings, then Developer (check in the dashboard). Sandbox and live keys are separate.
| Value | Adapter option | Env var |
|---|---|---|
| Merchant API key | apiKey | PEER_API_KEY |
| Webhook signing secret | webhookSecret | PEER_WEBHOOK_SECRET |
peer({
enabled: true,
apiKey: process.env.PEER_API_KEY!,
webhookSecret: process.env.PEER_WEBHOOK_SECRET!,
env: 'sandbox',
})Sandbox and production: set env: 'sandbox' with the sandbox key, or env: 'production' with the live key. env is required. The old value 'live' still works, with a deprecation warning.
Webhooks: register {baseUrl}/webhooks/peer with POST /api/v1/webhooks. Copy responseObject.secret from the answer to webhookSecret. Peer reports settlement only by webhook.
Gotchas: read the warning on the Peer page before you turn it on.
Reown (WalletConnect)
The wallet button in the Next.js example uses Reown (WalletConnect) for mobile wallets. Without a project id, only browser wallets work.
Access type: self-serve.
Sign up: dashboard.reown.com. Create a project. Copy the Project ID.
| Value | Where it goes | Env var |
|---|---|---|
| Project ID | examples/next-demo/lib/wagmi.ts | NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID |
# examples/next-demo/.env.local
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your-project-idGotchas:
- The project id is public by design. The browser needs it, so it is safe in a
NEXT_PUBLIC_variable. It is the only value on this page that is not a secret. - Check in the dashboard if you must add your domains to an allowlist for production.
Next steps
- Read the adapter page of each provider that you use, and its TO VERIFY notes.
- Test one webhook for each provider in the sandbox. See Webhooks to your backend.
- Go through the production checklist before real money moves.