Choose your integration
This is the first decision, and everything else in these docs hangs off it.
It is not "what kind of company are you". It is:
How much of payment collection do you want Wasp to own?
Collection means the part where a customer actually hands over a payment method: the card form they type into, the Google Pay™ or Apple Pay sheet, the encryption, the browser plumbing behind it. It is not the same thing as processing — sending the collected payment to be authorised and getting an answer. Wasp always owns processing. Collection is the part you get to choose.
There are four paths, grouped under three questions. The first question has a smaller choice inside it, which is why you will sometimes see them counted as three.
1. LET WASP OWN COLLECTION
│
├── Hosted Checkout
│ The customer pays on a Wasp page. You send them there and get a result.
│
└── Embedded Checkout
The customer stays on your page. The Wasp Checkout SDK collects.
├── Drop-in Wasp arranges the whole payment area for you
└── Headless You arrange the page; Wasp mounts each control into it
2. KEEP THE COLLECTION YOU ALREADY HAVE
│
└── Client-owned collection
Your own checkout collects, with no Wasp browser code at all.
Wasp prepares the payment method, you collect it, Wasp processes it.
3. THERE IS NOTHING TO COLLECT
│
└── Direct Payment API
You already hold the card, token or stored credential — from a
customer's saved payment method, a subscription, or a back-office
process. There may be no browser involved at all. You submit the
payment to be processed.
The third answer surprises people, so it is worth saying plainly: not every payment starts with a customer typing something. A subscription renewal, a saved card charged at dispatch, an invoice settled by your operations team — these have no collection step, because collection already happened. That is a legitimate Wasp integration, not a workaround.
Whichever you choose, the payment ends up in the same place: one payment call, made by your backend. There is no separate payment API per integration model, and none per payment method. The exact route, its request and its response are in the Merchant API reference and the implementation guides, which open once you have been granted access.
Which one is for you
| If this sounds like you | Choose |
|---|---|
| I want payments working with the least code, and I do not need the payment step to look like my site | Hosted Checkout |
| I want the customer to stay on my page, and I would rather not build payment UI | Embedded Checkout — drop-in |
| I want the customer to stay on my page, and I want to control the layout myself | Embedded Checkout — headless |
| I already have a checkout that collects cards or wallets, and I want Wasp to process the payments | Client-owned collection |
| I am a payment service provider with my own checkout serving my own merchants | Client-owned collection |
| I already hold a card, token or stored credential and just need it processed | Direct Payment API |
| I am charging a saved payment method for a subscription, renewal or repeat order | Direct Payment API |
A payment service provider is the clearest example of the last row, but it is not a different product and it is not a different API. A merchant with a mature checkout of its own chooses exactly the same path for exactly the same reason.
Words used throughout these docs
Read these once. They are used with these meanings on every page.
- Browser — the customer-facing page and its JavaScript. Never holds an API key or a signing key.
- Your backend — your server. This is where Wasp credentials live, and the only place that signs a Wasp request.
- Server-to-server — a call your backend makes to Wasp directly. Not a call made by browser JavaScript.
reference— your identifier for the payment. You choose it, you send it, every result and lookup is keyed by it. There is no second payment id.- Payment method — Card, Google Pay, Apple Pay. What the customer pays with.
- Payment instrument — what collection produced, in one shape whatever the customer paid with. Part of it is sealed: you forward it to your backend unchanged and never open it.
- Checkout Web Domain — a domain Stratsol has authorised your Wasp checkout to run on. One list, whatever payment methods you use.
- Return URL — somewhere a customer's browser can land after paying. It is a navigation destination and never proof that a payment succeeded.
1. Let Wasp own collection
Hosted Checkout
Your backend registers a checkout, Wasp gives you a URL, you send the customer there. Wasp owns that page completely — the payment methods, the card form, the wallet sheets, the authentication step if the payment needs one.
your backend registers the checkout with Wasp (server-to-server, signed)
↓
you redirect the customer to the Wasp page
↓
Wasp collects and processes the payment
↓
Wasp shows the customer the result, on the Wasp page
↓
the customer MAY choose "Return to merchant" — they may not
↓
your backend confirms the real result by reference,
or acts on the signed outcome notification
You write no browser payment code. You do not load the Wasp Checkout SDK.
The payment ends on the Wasp page, not on yours. Wasp shows the customer the terminal result there and offers a link back to you. Following it is their choice, and a satisfied customer often just closes the tab — so build for a return that never arrives. Anything in that return URL is informational. Confirm by
referencefrom your backend, or act on the signed outcome notification, before you fulfil anything.
Guide: Hosted Checkout.
Embedded Checkout
The customer never leaves your page. Your backend starts a checkout and receives one short-lived value; your page hands that value to the Wasp Checkout SDK, and the SDK does the collecting.
your backend starts the checkout with Wasp (server-to-server, signed)
↓ returns one short-lived value for the browser
your page gives that value to the Wasp Checkout SDK
↓
the SDK collects a payment instrument in your page
↓
your page hands the instrument to YOUR backend
↓
your backend submits the payment to Wasp, signed
The page states nothing about the payment — not the merchant, not the amount, not the currency, not the reference. All of that was fixed by the call your backend made, which is why a customer cannot edit it.
Guide: Embedded Checkout.
Drop-in
You give the SDK one container. It writes the whole payment area: every payment method your merchant has enabled, laid out and styled, in the light or dark presentation you asked for.
What that means in practice: you place one empty container on your page, hand the SDK the value your backend returned, and give it one function to call when it has collected something — which forwards the result to your own backend. The SDK does everything between: drawing the payment methods, collecting, submitting, closing the wallet sheet, and telling you the outcome. There is no second button to wire up and no branch per payment method.
The working code, with every option explained line by line, is in Drop-in.
Headless
You build the layout — headings, order, spacing, your own copy — and tell the SDK where each control goes.
What that means in practice: you create the checkout once, describe how a collected payment should be submitted and what to do with the result, and then mount each control — the Google Pay button, the Apple Pay button, the card fields — into elements you have positioned yourself.
The working code, with every option explained line by line, is in Headless.
Headless does not mean "no Wasp payment UI". The SDK still renders the card fields, still renders the wallet buttons, still does the collecting, and still finishes the payment its controls start. What you get back is control of the layout around them.
2. Keep the collection you already have
Client-owned collection. Your checkout stays yours. You load no Wasp browser code, you hold no Wasp key in the browser, and you keep collecting exactly the way you collect today. Wasp prepares each payment method server-to-server, you collect, and you submit the result to the same processing call everyone else uses.
your backend asks Wasp to prepare a payment method (server-to-server, signed)
↓
your own checkout collects it — your form, your wallet button, your page
↓
your backend submits the result to Wasp, signed
The sequence does not change when the payment method changes. Preparing Card, Google Pay and Apple Pay is the same call with a different value in it.
Guide: Client-owned collection.
3. There is nothing to collect
Direct Payment API. You already hold the payment credential, so there is no collection step to own or delegate. Your backend submits the payment to the same processing call every other model ends at, and Wasp processes it.
you already hold the card, token or stored credential
↓
your backend submits the payment to Wasp, signed
↓
Wasp processes it and answers
There is no Wasp browser code, no payment page and — often — no browser at all. A subscription billing run has no customer present to look at anything.
Two things make this a distinct path rather than a shortcut through the others:
- You supply the credential directly. The same payment call accepts either a card, token or stored credential you already hold, or the instrument Wasp collection produces. Same call, same result; you provide the first rather than receiving the second.
- Repeat payments are explicit. When you charge a credential the customer stored earlier, you say so on the payment, and link it back to the payment that set the series up. That is what tells Wasp this is a stored-credential payment rather than a fresh one, and it changes how it is presented to the card scheme.
This path carries obligations the others do not. Holding card data yourself brings PCI DSS scope, and charging a stored credential requires that you took the customer's agreement when you stored it. Wasp processes what you submit; it cannot supply a mandate you did not obtain. If you would rather not hold card data at all, one of the first two models keeps it out of your systems.
Guide: Payment API overview.
Headless is not client-owned collection
These two get confused, because "headless" sounds like "you own it". They are different in the one way that matters:
| Embedded headless | Client-owned collection | |
|---|---|---|
| Does your page load the Wasp Checkout SDK? | Yes | No |
| Who renders the card fields and wallet buttons? | The Wasp SDK | You |
| Who encrypts a card in the browser? | The Wasp SDK | You already do, however you do it today |
| Who runs collect → submit → close the wallet sheet? | The Wasp SDK | You |
| Who owns the layout around the controls? | You | You |
| What starts it? | Your backend starts an embedded checkout | Your backend asks Wasp to prepare a payment method |
Headless gives you the layout. Client-owned gives you the collection.
If you have no existing card-collection capability, headless is almost certainly what you want: Wasp collects the card, so the card never lands in your systems.
What is the same in all four
This is the point of integrating with Wasp once.
- One payment call, made by your backend, whichever model you chose.
- One payment identity. Your
reference, chosen by you, on everything. - One authentication model. Requests are signed by your backend. Browser code never holds a key.
- One result model.
200means Wasp decided — readpayment.approved, and do not treat HTTP 200 as approval.202means Wasp accepted the payment and has not decided it: readstatus, becauseauthentication_requiredcarries anactionfor the customer andprocessingcarries none and needs nothing of them. Either way the signed outcome notification finishes it, a failed authentication (W1) and an abandoned one (W2) included; a single lookup byreferencerecovers a notification that did not reach you. See Payment outcomes. - Payment methods are data, not new integrations. Adding Google Pay or Apple Pay to a merchant does not change the calls you make or the order you make them in.
- You never open a wallet payload. Whatever the wallet gave you is forwarded unchanged. Wasp decrypts it. You never receive, store or operate the keys that could.
What you have to build
The real question behind the choice. Each of these is your side of the line.
Hosted Checkout
You build: one signed server call to register the checkout, a redirect, and
a server-side confirmation by reference. That is the whole integration.
Wasp owns: the payment page, every control, collection, the provider interaction, customer authentication, and the payment itself.
Embedded Checkout — drop-in
You build: one signed server call to start the checkout, a container on your
page, a route on your backend that submits the payment, and a route that receives
Wasp's signed outcome notification — the result of any payment Wasp accepted
but could not decide in your request. That is either 202 shape: one waiting on
the customer, and one Wasp completes on its own with nothing asked of them.
The Wasp SDK owns: the layout inside the payment area, the controls, collection, browser encryption, when the payment is submitted, closing the provider's sheet, and the completion event.
Embedded Checkout — headless
You build: your page layout, the elements each control mounts into, the surrounding experience, and the same backend routes as drop-in — start, submit, and receive the outcome notification.
The Wasp SDK owns: the payment controls themselves, collection, browser encryption, the armed lifecycle, and provider completion. Exactly as in drop-in — you gained the layout, not the payment machinery.
Client-owned collection
You build: your page, your payment controls, your own provider and browser
collection, the signed call to Wasp's generic preparation, the signed submission of
what you collected, a route that receives Wasp's signed outcome notification for
either 202 shape, and — when one of them asks for the customer — a link that
opens Wasp's page
in a new tab.
Wasp owns: preparation, the Wasp and provider credentials, decryption of anything a wallet encrypted, customer authentication, processing, and the result.
Direct Payment API
You build: the signed submission of a card or stored credential you already hold, and a lookup by your reference for the rare payment whose answer never reached you.
Wasp owns: processing and the result. For the published examples, which
use entry: "Manual", that result comes back in the response: a keyed card has
no browser, so there is no authentication step and no notification to receive.
That is a property of those examples, not of the API. The same Direct call sent
with a browser entry type such as "Digital" — including a stored-card charge
you start — can be answered 202 and completes through a signed outcome
notification like any other. If you use one, configure a callback and handle
both 202 shapes. Holding card data brings obligations the other models
keep away from you.
At a glance
| Hosted | Embedded drop-in | Embedded headless | Client-owned | Direct | |
|---|---|---|---|---|---|
| Payment page | Wasp | You | You | You | None |
| Payment-area layout | Wasp | Wasp | You | You | None |
| Card fields / wallet buttons | Wasp | Wasp | Wasp | You | None |
| Browser card encryption | Wasp | Wasp | Wasp | Yours, or raw card details over your signed backend call | None — you hold the card |
| Collect → submit → close the sheet | Wasp | Wasp | Wasp | You | Submit only |
Amount, currency, reference | Your backend | Your backend | Your backend | Your backend | Your backend |
| Submitting the payment to Wasp | Wasp | Your backend | Your backend | Your backend | Your backend |
| Wallet decryption | Wasp | Wasp | Wasp | Wasp | — |
| Customer authentication (3DS) | Wasp, end to end | Wasp, SDK opens the step | Wasp, SDK opens the step | Wasp, you open the step | Not for the Manual examples; possible with a browser entry type |
| How your backend learns the result | One check by reference, or a notification — not the customer's return | The response, or a signed notification | The response, or a signed notification | The response, or a signed notification | The response; a signed notification if you use a browser entry type |
Customer authentication, in each model
Some payments need the cardholder to prove who they are before they can be approved. Wasp runs that authentication in every model. What differs is only how much of the browser journey you write.
| Model | What you do |
|---|---|
| Hosted | Nothing. The Wasp page runs it, then shows the result and offers a link back. You never see a 202. |
| Embedded | Your backend tells the SDK in its own vocabulary: { "paymentStatus": "actionRequired", "action": { "url": … } } when the 202 carries an action — the SDK opens it — or { "paymentStatus": "processing" } when its status is processing and nothing is asked of the customer. Do not pass Wasp's 202 body through unchanged: it has no paymentStatus, so the SDK reports failed. See What your backend returns to the browser. Either way the result arrives at your backend as a signed notification. |
| Client-owned | Open the action in a new tab from your page. The result arrives at your backend as a signed notification. |
| Direct | Nothing for the Manual examples. With a browser entry type, as for client-owned. |
The payment is never resubmitted. A 200 is the result; after a 202 the result
arrives as a signed notification. A lookup by reference is only for recovering a
result whose one notification attempt did not reach you, including a W1 failed
authentication or a W2 abandonment.
See Customer authentication.