The createSessionRouteHandler shipped with the App Kit SDK is a drop-in
session route for any host that uses the Fetch API standard (Next.js, Hono,
Cloudflare Workers, Bun, Deno, modern Node). The default handler is
unauthenticated. Most apps need to customize it in these areas:
- Authenticate so only signed-in users can mint sessions.
- Log or inspect session minting failures.
- Mint sessions from a host that does not use the Fetch API.
Add authentication
On Fetch-compatible hosts, create the handler once with
createSessionRouteHandler and register it as POST /api/onramp/sessions in
your router. See the
embed widget quickstart for a full
example.
Add an authorize callback. The callback runs before the body is validated and
can return true (allow), false (reject with 401), or throw a KitError
(rejected with the corresponding status):
You can also validate that the request body matches the signed-in user:
The handler’s body validation runs after authorize returns, so an
unauthenticated request is rejected with 401 before any payload is parsed.
Customize error handling
createSessionRouteHandler maps thrown errors to HTTP status codes
automatically. Using the same server and handleOnrampSession from above,
pass an onError callback:
onError runs after the error is mapped to a response, so the response is still
returned. The callback is for observability. It does not change the status code
or body.
See the error handling reference
for the full error to status mapping.
Use a non-Fetch host
createSessionRouteHandler only works on runtimes that pass standard Request
objects. Express and Fastify pass their own request and response objects, so
call server.onramp.createSession() directly instead. You’re now responsible
for the error mapping the Fetch handler did automatically.
Map KitError.type to HTTP status the same way createSessionRouteHandler
does. See the
HTTP status code mapping
for the full mapping. Shape error response bodies to match your API.
Add authentication in front of this route, like any other endpoint in your app.
By default, the Onramp widget shows its full catalog of supported tokens and
blockchains. If your app only handles a subset, pass an assets object on the
session request to narrow what the widget’s selector displays.
You can set any of three fields:
-
tokens: an array of token symbols such as USDC, EURC, or ETH. The
widget shows those tokens on every blockchain that supports them.
-
chains: an array of blockchains, matched by either the network id (arc,
base, ethereum) or the display label (Arc, Base, Ethereum). Matching
is case-insensitive. The widget shows every supported token, restricted to
those blockchains.
-
pairs: an array of exact token and blockchain combinations. Use this when
you need finer control than tokens and chains allow.
If you set more than one field, the widget only shows options that match every
field you set. Omit assets to show the full set of supported tokens and
blockchains. See
Supported blockchains and tokens
for the current list.
assets scopes what the selector displays. It doesn’t override the widget’s
eligibility, geo, or quote logic. A token or blockchain listed in assets can
still be unavailable for a specific user if they’re geo-blocked or otherwise
ineligible.
Allow your page to embed the widget
The widget page enforces a frame-ancestors Content Security Policy so only
approved parent sites can embed it. The allowlist is built from a
referrerDomain you set when constructing the server kit.
Pass it as a bare hostname on createAppServerKit:
Keep the following in mind when setting referrerDomain:
- Format: Use a single bare hostname such as
app.example.com or
localhost. Don’t include a scheme, port, or path.
- Source: Derive
referrerDomain server-side from your app’s
per-environment config. A browser-supplied Origin or Referer header would
let attackers widen the allowlist.
- Sandbox:
referrerDomain isn’t enforced. Set it anyway to verify your
wiring before promoting to production.
- Production: Debit card, Apple Pay, and Google Pay flows fail with a 403 if
the domain isn’t registered in your KYB’s
web_url entries.