Accept payments
Hosted checkout
Send customers to a payment page that Whitechain Commerce serves, with no frontend code on your side.
Every checkout session has a url field. It points to the hosted checkout page, /checkout/:sessionId on the Whitechain Commerce dashboard. The page renders the same checkout widget you can embed, centered on its own page, and sends the customer back to your successUrl after they pay.
How it works
- Your server creates a checkout session with your secret key, including a
successUrland acancelUrl. - You redirect the customer to the session's
url. - The customer connects a wallet and pays in USDT. The funds go straight from their wallet to your payout wallet.
- Once the backend has verified the payment onchain, the page redirects the customer to your
successUrl. - Your server receives a signed
payment.succeededwebhook and fulfils the order. See Webhooks.
The checkout URL
Always use the url returned by the API. For example, https://whitechain-dashboard.vercel.app/checkout/cs_....
url is part of the secret view of a session (CheckoutSession), returned when you create it with your secret key. The public view (GET /api/v1/checkout_sessions/:id, used by the widget) does not include it.
Create a session
With curl:
curl -X POST https://whitechain-dashboard.vercel.app/api/v1/checkout_sessions \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"orderId": "order_123",
"amount": "4.99",
"successUrl": "https://store.example.com/orders/order_123",
"cancelUrl": "https://store.example.com/"
}'
The response is the full session, including "url": "https://whitechain-dashboard.vercel.app/checkout/cs_...". A new session returns HTTP 201. If an unexpired open session (or a processing one) for the same orderId and amount already exists, the API returns it with HTTP 200.
With the server helper:
import { createCheckoutSession } from "@whitechain-commerce/react/server";
const session = await createCheckoutSession({
apiBase: "https://whitechain-dashboard.vercel.app",
secretKey: process.env.WC_SECRET_KEY!, // sk_test_...
orderId: "order_123",
amount: "4.99",
successUrl: "https://store.example.com/orders/order_123",
cancelUrl: "https://store.example.com/",
});
// session.url === "https://whitechain-dashboard.vercel.app/checkout/cs_..."
For every parameter and error, see createCheckoutSession and the API reference.
Redirect the customer
Redirect from your server so the amount and secret key never touch the browser. This Next.js route handler creates a session and answers with a 303 redirect, so a plain HTML form can start the checkout:
// app/api/checkout/route.ts
import { createCheckoutSession } from "@whitechain-commerce/react/server";
export async function POST() {
const orderId = `order_${Date.now()}`;
const session = await createCheckoutSession({
apiBase: process.env.WC_API_ORIGIN ?? "https://whitechain-dashboard.vercel.app",
secretKey: process.env.WC_SECRET_KEY!,
orderId,
amount: "4.99",
successUrl: `https://store.example.com/orders/${orderId}`,
cancelUrl: "https://store.example.com/",
});
return Response.redirect(session.url, 303);
}
<form action="/api/checkout" method="POST">
<button type="submit">Pay with USDT</button>
</form>
Return URLs
Both URLs are optional. Each must be an http or https URL of at most 2048 characters.
| Field | What the hosted page does with it |
|---|---|
successUrl |
After the payment is verified, the page shows "Payment confirmed. Taking you back to the store…" and redirects there after 2 seconds. The success screen also has a "Return to store" button linking to it. |
cancelUrl |
Shows a "Cancel and return to store" button while the customer is choosing a wallet, switching networks or reviewing the payment. Clicking it navigates there. If the session has expired, the expired screen has a "Return to store" button linking to it. |
Details:
- The page does not add query parameters to either URL. Put whatever you need to find the order, such as your order id, in the URL itself.
- If a customer opens the page for a session that is already paid, it shows "This order is already paid" and does not redirect on its own. The "Return to store" button still links to
successUrl. - Without a
successUrl, the customer stays on the success screen. - Without a
cancelUrl, there is no cancel button and the expired screen has no return button. - Reaching
successUrlis not proof of payment. Anyone can open that URL. Fulfil orders only from a verifiedpayment.succeededwebhook.
Query parameters
The hosted page reads one query parameter:
| Parameter | Values | Default | Description |
|---|---|---|---|
theme |
dark |
Light | ?theme=dark renders the checkout card in the dark theme. Any other value, or none, renders it in the light theme. |
https://whitechain-dashboard.vercel.app/checkout/cs_...?theme=dark
The theme changes the checkout card. The page around it always has a dark background.
What the customer sees
The page has a "Whitechain Commerce" header with a "Secure checkout" badge, the checkout card in the middle, and a footer that says "Funds go straight from your wallet to the merchant on Whitechain. We never hold your money." Search engines are asked not to index it.
The card shows your merchant name, the order id, the amount in USDT and a countdown to the session's expiry (sessions last 30 minutes from creation). The customer then goes through the same steps as in the embedded widget: choose a wallet, switch networks if needed, check the balance, approve the exact amount if needed, pay and wait for verification. See What the customer sees for each screen, including expired sessions, errors and wallet rejections.
If the session id does not exist, the card shows "We couldn't load this checkout" with the API's error message (for example No checkout session cs_123.) and a "Try again" button.
Hosted or embedded
| Hosted checkout | Embedded widget | |
|---|---|---|
| Frontend code | None. Redirect to session.url. |
Render <WhitechainCheckout /> in your React app. |
| Where the customer pays | On the Whitechain Commerce domain. | On your own page, next to your order summary. |
| After payment | Automatic redirect to successUrl after 2 seconds. |
Your onSuccess callback decides. The widget does not redirect on its own. |
| Cancel | Navigates to cancelUrl. |
Your onCancel callback, or cancelUrl if you do not pass one. |
| Theme | ?theme=dark query parameter. |
theme prop. |
| Requirements | Any backend that can make an HTTP request. | React 18 or later and the workspace package @whitechain-commerce/react. |
Use the hosted checkout when you are not on React, want the fastest integration, or prefer to keep payment UI off your site. Use the embedded widget when you want the customer to stay on your page and control what happens after payment.
Either way, the session, the onchain payment and the webhooks are the same.
Limitations
- USDT is the only currency.
- The hosted page has no merchant branding beyond your merchant name. There are no logo or color settings.
themeis the only query parameter.