Overview
Chainrails aggregates fiat ramp providers behind one API. A user can on-ramp fiat into USDC on a supported destination chain, or off-ramp supported tokens from a source chain into local fiat. There are two execution flows:
For headless providers, Chainrails has been built to minimize KYC friction. You only need to KYC once per user to access multiple liquidity providers, and you can submit only the fields that are missing or insufficient for each selected provider.
Before you begin
You need:- a Chainrails account;
- a test or live API key from the Chainrails dashboard;
- completed Chainrails KYB to access live fiat endpoints;
End-to-end flow
The integration sequence is:- Retrieve supported countries for the requested direction and amount.
- Request quotes using the selected country and currency.
- Select a quote and inspect its
transferTypeandfieldsRequired. - For a headless quote, complete the Chainrails KYC loop.
- Create the ramp order using the selected provider.
- Show
transferInstructionsfor a headless order or openwidgetUrlfor a hosted order. - Poll the order until it reaches a terminal status.
1. Retrieve supported countries
Use the countries endpoint to build your country and currency selector:- cURL
- JavaScript
- PHP
- cURL
- JavaScript
- PHP
2. Request quotes
On-ramp quote
- cURL
- JavaScript
- PHP
Off-ramp quote
- cURL
- JavaScript
- PHP
An abbreviated quote response looks like this:
recommended quote creates a balance between price, remaining KYC friction, pending or blocked KYC state, and direct-flow availability.
3. Determine whether KYC is required
Inspect the selected quote’s payment channel:widgetUrl; the provider owns the verification flow.
Inspect provider requirements
This endpoint describes the applicable policy without inspecting a user:- cURL
- JavaScript
- PHP
assurance: "provided" means Chainrails needs a stored value. assurance: "verified" means the field must be validated by an accepted verification source.
Get the user’s KYC state
- cURL
- JavaScript
- PHP
Continue directly to order creation when:
blocked is true, show a message asking the user to contact support. Do not repeatedly resubmit the same identity data.
4. Complete headless KYC
KYC submission uses one endpoint for profile creation, field storage, text-document checks, and hosted external verification:userEmail, provider, countryCode, and fiatCurrency are required. Include any user information you already have/can obtain in fields (derived from checking provider’s requirements); the engine determines what can be stored, validated, or sent to an external verification flow.
countryCode is the transaction corridor country. fields.country is the user’s current country of residence. They are intentionally separate and do not always need to match.Text verification flow
The text verification flow provides the least friction. Currently available for just Nigeria, but will be expanded to more countries in the future. Submit the available profile fields and required text documents:- cURL
- JavaScript
- PHP
BVN and NIN in the public submission payload. Both values must contain exactly 11 digits.
Chainrails validates the documents and compares the returned identity against the submitted names and DOB. Phone and address are mutable fields and do not need an exact registry match.
External document and biometric verification
Outside Nigeria, Chainrails requires theexternal_verification capability. You can start with only the fields you already have:
- cURL
- JavaScript
- PHP
verification.url in the same tab, a new tab, or an embedded browser appropriate for your application. callbackUrl controls where the hosted flow returns the user.
Chainrails receives the provider webhook asynchronously. Returning to callbackUrl does not by itself mean KYC is approved. Poll GET /api/v1/ramp/kyc until one of these outcomes occurs:
canProceed: true— continue to order creation;pendingRequirementsis non-empty — keep waiting and poll again;blocked: true— stop and direct the user to support;- missing or insufficient fields remain — collect and submit only those fields.
Progressive KYC loop
Do not render one large static form. Build the next form from the latest state:- Read
missingRequirements,rejectedRequirements, andinsufficientRequirements. - Ask only for those field requirements, dependent on what the provider needs.
- Submit the fields to
/api/v1/ramp/kycwith the same provider and corridor context. - If a verification URL is returned, send the user through it.
- Poll
/api/v1/ramp/kyc. - Continue when
canProceedis true.
5. Create the ramp order
quoteId.
Headless on-ramp order
- cURL
- JavaScript
- PHP
fieldsRequired. A field with required: false can be omitted.
Example headless response:
Widget on-ramp order
For a quote withtransferType: "widget", do not call the Chainrails KYC endpoints first:
- cURL
- JavaScript
- PHP
widgetUrl. The provider collects its own KYC and payment information there. Do not send Chainrails KYC documents through the order fields object.
Headless off-ramp order
Off-ramp quotes expose payout fields and, where applicable, selectablenetworkId options. Use the option values exactly as returned by the quote.
- cURL
- JavaScript
- PHP
6. Handle KYC order errors
Order creation revalidates KYC against the selected provider. This protects against stale frontend state. If KYC is incomplete, the order endpoint returns a400 response with:
KYC_BLOCKED, stop automatic retries and ask the user to contact support.
7. Monitor the order
Get one order
- cURL
- JavaScript
- PHP
Get an on-ramp order by intent address
- cURL
- JavaScript
- PHP
List orders
- cURL
- JavaScript
- PHP
Poll every few seconds or subscribe to the ramp order webhooks to receive status updates.
Optional order actions
Cancel an order
- cURL
- JavaScript
- PHP
Confirm an order
Some provider flows can require explicit confirmation after the user completes a deposit action:- cURL
- JavaScript
- PHP
Implementation checklist
- Use
/ramp/countrieswithtypeandamountto build corridor selection. - Request quotes with
countryCodeanduserEmail. - Select the provider from the quote response rather than hardcoding one.
- Inspect
transferTypeto choose the headless or widget flow. - For headless ramp flows, poll
/ramp/kycand submit only outstanding requirements. - Treat
countryCodeas transaction geography andfields.countryas residence. - Redirect users through
verification.urlwhen external verification is required. - Wait for
canProceed: truebefore creating a headless order. - Send only quote-defined payment fields in the order
fieldsobject. - For widget flows, redirect to
widgetUrland let the provider own KYC. - Display exact transfer instructions and expiry values from the order response.
- Poll the order until a terminal status is reached.

