2026-10-05
Hosted Checkout vs Payment API: How to Choose for Crypto Payments

A provider's hosted checkout page looks like the fastest way to accept crypto: create a payment, redirect the buyer, wait for the success callback. But hosted checkout vs payment API isn't really about implementation speed. It's about who controls the payment flow and who owns the screen at the moment a customer decides to pay. In crypto there's a third question: does anyone sit between your business and its funds?
For a prototype, a hosted page is often the right call. For a product where paying is part of the experience, it tends to become an architectural constraint dressed up as convenience. Which one fits depends on how much product logic has to run when the money moves.
What actually differs
A hosted checkout sends the customer to a page the provider runs, or drops a widget the provider controls into yours. The provider draws the payment UI and shows the status. When it's done, the customer is sent back to you. Your integration starts with creating a payment and ends with a redirect, a webhook, or both.
A payment API hands your application the primitives instead. Your backend creates a charge and your frontend draws the checkout however you want. Payment state reaches your systems through webhooks, a live event stream or SDK calls. The provider supplies infrastructure, not a replacement for your checkout.
In crypto, that difference gets sharper. An API can give you a deterministic address for each charge, watch the chain and report the result while the buyer stays in your product. A hosted page does the same work behind the scenes. It just decides how the customer meets it.
Checkout and custody are separate questions
Comparison posts usually blur this part: neither model tells you who holds the money. A hosted page can settle straight to a merchant wallet. An API can route every payment into an account the processor controls. So there are two things to check, and they're checked separately:
- Who owns the screen? That's hosted vs API.
- Who can move the funds after the customer pays? That's custodial vs non-custodial.
We built Klappay so one charge serves every checkout style. The same Charge object carries a checkoutUrl for our hosted page and the raw address and acceptedPayments for building your own. Either way the payer sends funds to the same per-charge address. That address is a routing contract that pays out to your wallet and any split recipients, and nobody can redirect it, us included. Switching checkout styles changes nothing about custody.
That's the property to check with any provider: does the payment address belong to the charge and pay out to you, or does it belong to the processor and credit an internal balance?
Why hosted checkout is attractive
A hosted page cuts the UI and payment state your team has to build. That matters when checkout isn't central to the product or when you sell a fixed-price item with nothing custom after payment. It also matters when you need to launch this week.
The provider also takes the edge cases that would otherwise land on you: payers with three wallet extensions installed, network switching, QR fallbacks. Our hosted page takes a connected wallet, a QR code or the raw address, and it updates live while the transfer confirms.
There's a support benefit too. When the customer is on the provider's page, the provider's interface explains what's supported and what went wrong.
The cost is that the provider's choices become your product decisions. Its wallet UX, timeouts and error copy all show up at the moment your customer decides whether to pay. You can usually change a logo and a color. You can't change the flow.
Where hosted flows start to break
Redirects break context. A customer leaves a marketplace listing or a SaaS upgrade screen and lands somewhere that doesn't know why they're paying. Sending them back afterward doesn't undo the interruption. On mobile it's worse, because approving in the wallet already opens another app.
A redirect isn't proof of payment. Browsers close, the return URL fails to load, and customers come back through a bookmark. Confirmations arrive on the chain's schedule anyway. You still need backend verification and idempotent fulfillment. A lot of the simplicity of a hosted page is UI simplicity. Your backend work barely shrinks.
Product rules end up in metadata fields. A subscription upgrade has to attach a payment to an account, a plan change, an invoice period, and an entitlement. A generic checkout page can only carry that as metadata and hand it back afterward. The real logic then runs in reconciliation, after the customer has left.
That's tolerable for a while. Once payments carry logic specific to your product, the checkout is a thin layer over a business workflow. Give that layer away and you end up designing around someone else's abstractions.
The middle path: components, not pages
"Hosted" and "API" aren't the only options. Between them sits a component library that runs inside your app while you own the state.
@klappay/checkout-kit is the same code that runs Klappay's hosted page, extracted into a package. It turns a charge into what a payment screen needs and handles the wallet side. Your app keeps the layout, the routing and what happens after the payment confirms.
Keep one distinction in mind: an embedded widget isn't an API integration. If the provider's component owns the state machine and you can only style it, you're still in a hosted model, only embedded in your page. The test is whether your code decides what the customer sees next.
What an API checkout asks of your team
API control isn't free. It moves responsibilities into your stack, which is where they belong if payments are core to your product.
Your backend creates the charge: price, accepted networks, a short expiry, your order reference and the split. Here's a marketplace order paying a seller 95% and the platform 5%:
const charge = await klap.charges.create({amount: 49,acceptedPayments: [{ token: 'USDC', network: 'base' }],expiresIn: 900,externalRef: order.id,splitRecipients: [{ recipientId: seller.recipientId, percent: 95, label: 'seller' },{ recipientId: platform.recipientId, percent: 5, label: 'platform' },],})await orders.markAwaitingPayment(order.id, charge.id)
From there the two styles share almost everything. A hosted integration redirects to charge.checkoutUrl. An API integration shows charge.address and charge.acceptedPayments in its own screen. Both should fulfill the order from a verified charge.confirmed or charge.settled webhook. The browser saying the transfer went through is never enough.
The frontend work is real, though. You show the right action for the payer's wallet and network. After the transaction is submitted you show a pending state until the webhook arrives. And you recover when the customer refreshes or opens the checkout on another device. The live event stream needs your secret API key, so your backend holds it and relays progress to the browser over your own channel. None of that is crypto-specific. It's what owning a distributed flow looks like.
Choose by the job, not the demo
Choose hosted checkout when speed matters more than owning the checkout, the payment path is simple, and the provider's interface is acceptable as part of your product. Check where the funds settle before you treat it as the low-risk shortcut.
Choose an API when payment state drives entitlements, fulfillment, splits or subscriptions. It's also the fit when your team needs full control over the UI, wallet behavior and recovery paths.
Choose components when you want to own the screen without rebuilding wallet plumbing.
Whatever you pick, run one test before you sign up: if the provider disappeared right after a transaction was broadcast, would the funds still end up in the wallets you intended, and would your application have enough data to reconcile the order? With direct settlement, the first answer is yes regardless of who drew the payment screen. The second depends on whether you stored the charge ID next to your order.