Payments
The redirect-and-reconcile payment flow, and how the cart clears itself afterward.
StoreKit uses a hosted redirect payment flow (PhonePe). You never handle card data — you redirect the shopper to the provider and reconcile when they come back.
The flow
Create the checkout. checkout.create() returns a redirectUrl to the payment provider.
Redirect the shopper to redirectUrl.
The provider redirects back to your storefront's return page (configured via STOREFRONT_URL), with ?orderId=... in the URL.
Confirm the order on your return page. The SDK polls/reconciles the payment and tells you success, pending, or failure.
The return URL
The provider needs to know where to send the shopper back. That origin comes
from your STOREFRONT_URL (or initStorekit({ baseURL })). The API builds the
return URL as <your-origin>/payment/callback?orderId=<id>.
If STOREFRONT_URL is unset, the Next.js adapter warns and payment returns may
land on the wrong origin. Always set it in production.
Confirming on the return page
In a Next.js client component, usePaymentConfirmation() does the work:
"use client";
import { useSearchParams } from "next/navigation";
import { storefront } from "@/lib/storekit-client";
export default function PaymentCallback() {
const orderId = useSearchParams().get("orderId");
const { status, order, message, retry } =
storefront.usePaymentConfirmation(orderId);
switch (status) {
case "processing":
return <p>Confirming your payment…</p>;
case "success":
return <p>Thanks! Order {order?.id} is confirmed.</p>;
case "pending":
return <p>{message} <button onClick={retry}>Check again</button></p>;
default:
return <p>{message ?? "Payment failed."} <button onClick={retry}>Retry</button></p>;
}
}The status can be:
| Status | Meaning |
|---|---|
processing | Awaiting the first confirmation response. |
success | Payment confirmed. |
pending | Provider webhook still settling — offer a "Check again" button. |
failed | Payment was rejected. |
error | The confirmation call itself failed (network) after retries. |
The cart clears itself
On a successful payment, the API clears the customer's cart. The
usePaymentConfirmation hook also refreshes the shared cart state, so a header
cart badge drops to zero without any extra code.
Confirming without React
Outside React, call checkout.confirm(orderId) yourself:
const { data, error } = await storekit.checkout.confirm(orderId);
// data → { success, status, order, error? }It's safe to call more than once. If the provider's webhook hasn't landed yet,
status is pending; retry shortly.
Webhooks (server-to-server)
The provider also calls your API directly via webhooks to settle the order authoritatively, independent of the browser redirect. You don't build these — they're part of the API. See API → Webhooks.