Payments
Take payment for an order row: offline (pay at pickup) always, card through the owner's connected Stripe account. The amount is always computed on the server from the order's line rows.
On this page
Payments act on the contract's basket: an order entity, its line entity and the catalog price field. Create the order and its line rows first, then check out.
app.pay
app.pay.methodsmethod
What the app accepts right now: always "offline", plus "card" once the owner has connected Stripe.
app.pay.methods(): Promise<Array<"offline" | "card">>- Returns
- Array<"offline" | "card">. Falls back to ["offline"] when the runtime has no payment plane.
- Errors
- Does not throw.
- Permissions
- Any caller of the app.
const methods = await app.pay.methods();
const canPayByCard = methods.includes("card");Source: packages/appkit/src/kits/primitives/app-handle.ts:141
app.pay.checkoutmethod
Record payment for an order row. "offline" records it as due. "card" creates a Stripe Checkout session and sends the user to Stripe; they come back to this page with ?appbricx_pay=success&order=<id>, where you call confirm. If a card payment can't be started the order stands and is recorded as offline with a note.
app.pay.checkout(orderEntity: string, orderId: string, method?: "offline" | "card"): Promise<AppCheckout>Parameters
| Name | Type | Description |
|---|---|---|
orderEntityrequired | string | The contract's order entity (the basket's order table). |
orderIdrequired | string | The order row's id. |
methodoptional | "offline" | "card" | "offline" (default) or "card". |
- Returns
- AppCheckout: { method, status ("due" or "processing"), amountCents?, fallback?, note? }. amountCents is the total the server computed from the order's line rows times catalog prices.
- Errors
- "payments aren't available in this preview" without a runtime.
- The server's message: NOT_AN_ORDER (the table isn't the basket's order entity), ORDER_NOT_FOUND (the caller can't read the order), BAD_REQUEST.
- Permissions
- The caller must be able to read the order through row-level security. The browser never sends an amount.
const order = await app.create("orders", { note });
for (const line of cart) await app.create("order_lines", { order: order.id, item: line.id, qty: line.qty });
const res = await app.pay.checkout("orders", String(order.id), "card");
if (res.fallback) setNotice(res.note ?? "Pay at pickup.");Source: packages/appkit/src/kits/primitives/app-handle.ts:146
app.pay.confirmmethod
Back from Stripe: asks Stripe about the order's open card payment and marks it paid, failed or still processing.
app.pay.confirm(orderEntity: string, orderId: string): Promise<string>Parameters
| Name | Type | Description |
|---|---|---|
orderEntityrequired | string | The order table. |
orderIdrequired | string | The order id. |
- Returns
- The status: "paid", "failed" or "processing".
- Errors
- "card payments aren't available in this preview".
- ORDER_NOT_FOUND, NO_CARD_PAYMENT, STRIPE_NOT_CONNECTED (503), STRIPE_ERROR (502), PAYMENT_MISMATCH (the Stripe session belongs to another order).
- Permissions
- Only someone who can read the order may confirm it, and the answer comes from Stripe, never from the browser.
const back = app.pay.returned();
if (back?.status === "success") {
const status = await app.pay.confirm("orders", back.orderId);
setPaid(status === "paid");
}Source: packages/appkit/src/kits/primitives/app-handle.ts:149
app.pay.returnedmethod
On the page Stripe sent the user back to: which order, and whether they paid or cancelled. Reads ?appbricx_pay and ?order from the URL.
app.pay.returned(): { status: "success" | "cancelled"; orderId: string } | null- Returns
- { status: "success" | "cancelled"; orderId } or null on any other visit.
- Errors
- Does not throw.
- Permissions
- Reads the URL only. A "success" here is a claim: confirm asks Stripe.
useEffect(() => {
const back = app.pay.returned();
if (back?.status === "cancelled") setNotice("Payment cancelled. Your order is saved.");
}, [app]);Source: packages/appkit/src/kits/primitives/app-handle.ts:152
app.pay.statusmethod
The order's latest payment.
app.pay.status(orderEntity: string, orderId: string): Promise<AppPayment | null>Parameters
| Name | Type | Description |
|---|---|---|
orderEntityrequired | string | The order table. |
orderIdrequired | string | The order id. |
- Returns
- AppPayment { method, provider, status, amountCents, currency, createdAt }, or null when none is recorded.
- Errors
- "payment status isn't available in this preview"; ORDER_NOT_FOUND when the caller can't read the order.
- Permissions
- Gated on reading the order row through row-level security.
const p = await app.pay.status("orders", id);
if (p) setLabel(`${(p.amountCents / 100).toFixed(2)} ${p.currency.toUpperCase()} · ${p.status}`);Source: packages/appkit/src/kits/primitives/app-handle.ts:154
Types
type AppCheckout = {
method: "offline" | "card";
status: string;
amountCents?: number;
fallback?: boolean;
note?: string;
}Source: packages/appkit/src/kits/primitives/app-handle.ts:118
type AppPayment = {
method: string;
provider: string | null;
status: string;
amountCents: number;
currency: string;
createdAt: string;
}Source: packages/appkit/src/kits/primitives/app-handle.ts:127