The facilitator’s role
The Buckspay facilitator is the off-chain relay service that takes a signed Stellar authorization entry, wraps it in a fee-bump transaction, and submits it to the network. It is what makes the payment gasless: the facilitator’s sponsor account sources the XLM fee so the payer does not need any. In the SDK the facilitator is represented as aRelayer - the third config slot in
createBuckspayClient. You construct one with buckspayFacilitator({ url, network }) from
@buckspay/relayer/buckspay-facilitator.
The same-origin BFF boundary
The facilitator authenticates callers via an API key. The API key must never reach the browser. A browser bundle is inspectable by any user; shipping the key client-side exposes it to replay attacks and quota abuse. The standard pattern is a Backend for Frontend (BFF) route on your own server:- The browser runs
prepare()andsign(), then POSTs theSignedIntentto your backend. - Your backend validates business rules (intent not expired, amount within tolerance, etc.).
- Your backend calls
server.send(signed)using acreateBuckspayClientthat is configured withbuckspayFacilitator({ url, apiKey, network })- theapiKeyis an environment variable, never bundled.
RelayPayload that send() forwards is byte-identical to what the facilitator expects -
the BFF is a pass-through after your validation, not a translation layer.
BFF example
The example below is the canonical server-side pattern. It is the only Buckspay example that passes anapiKey - all browser examples omit it and point url at a same-origin route
like /api/gasless.
What stays in the browser
The browser-sidebuckspayFacilitator call omits apiKey entirely and points url at your
BFF route:
POST /relay to that route with the serialized RelayPayload. Your BFF
handler validates, then calls the real facilitator with the key.
Migration from direct fetch
If you currentlyfetch the facilitator directly from a backend route (hand-building the
SorobanRelayBody), the migration is:
- Delete the hand-rolled
signTransferAuth/normalizeSignaturehelpers -walletsKitabsorbs the double-encode quirk of Freighter automatically. - Replace the raw
fetchwithserver.send(signed), whereserveris acreateBuckspayClientwithbuckspayFacilitator({ url, apiKey, network }). - Keep your rail schema and BFF route path unchanged.
Next
Networks
Testnet vs. pubnet, the mainnet opt-in, and USDC decimals.
Prepare -> Sign -> Send
The three-phase flow and where the BFF slot fits in.

