> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heretic.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Protected checkout

> Check an order before allocating stock and queueing payment.

Prepare a browser measurement while the visitor browses. At checkout, apply your policy before creating the order. Existing signed-in visitors reuse a current measurement; an early submission waits only when a required check is still pending.

The [Next.js and PostgreSQL example](/integration/nextjs-postgres) includes a checkout page at `/checkout`. It creates an order and a payment task in PostgreSQL. It does not collect card details or call a payment provider.

## Submit the cart

The example has a single-product cart. The browser sends a product ID and quantity:

```js theme={"dark"}
const outcome = await client.execute('checkout', {
  sku: 'NOTEBOOK',
  quantity: 2
});
```

The server derives the account from the authenticated session. It reads the price and available stock from the product table. Client-supplied prices or account IDs cannot change the order.

`app/checkout/page.jsx` contains the complete form, catalog loading, error handling, retry controls and receipt display. `lib/actions.mjs` contains the corresponding server action. Both ship in the archive.

## Check policy and create the order

The `checkout` action requires an authenticated account and a quantity between one and five. It uses `checkout:<sku>` as the shared resource key, then locks and checks that product's stock. All contenders for the same product use the same key, across application instances.

Its sample policy requests a ceremony when the measurement is not `uncontradicted`. A passed ceremony permits the policy to continue, but stock and account checks still apply. Stock is checked again after a ceremony; submitting earlier does not reserve an item.

Once policy allows the action, `commit` performs three writes with the same PostgreSQL transaction client:

| Write                   | Stored result                                                               |
| ----------------------- | --------------------------------------------------------------------------- |
| Update product stock    | Subtract the validated quantity without allowing negative stock.            |
| Insert the order        | Save the account, product, quantity, server-calculated amount and currency. |
| Insert the payment task | Save the order ID, amount, currency and a stable payment idempotency key.   |

The SDK saves the completion receipt in that transaction too. If any write fails, the stock change, order and outbox entry roll back together. Retrying the same attempt returns the saved order when it already completed.

Intentional repeat purchases are allowed. The example does not apply redemption's one-per-account or identifier-match rule to checkout.

## Deliver payment separately

The reference ends with `example_payment_outbox`. Connect it to your existing payment worker. Each row contains a stable `idempotency_key` of `checkout:<attemptId>` and the order's stored amount and currency.

Your worker should claim pending work durably, use that key for repeated provider requests, and record the provider's result. Reconcile provider webhooks or status reads with the order in your own database. A lost response is not proof that payment failed. Database completion alone does not guarantee exactly-once execution by an external provider.

The order is `awaiting-payment` until your payment flow updates it. Choose an explicit payment deadline, cancellation policy and stock-release transaction. Preserve payment/order receipts for the retry and reconciliation window. The local example does not run an outbox worker or expire orders automatically.

For a cart with several products, replace the single-product transaction with your existing cart transaction and lock stock rows in a consistent order. Preserve your checks for discounts, tax, delivery, currency and payment eligibility. Use the same protected write path for every endpoint that can create the order.

## Exercise the example

1. Select Account one, choose Notebook and place an order. The receipt shows the server-calculated total and payment-pending state.
2. Retry that attempt. The order and outbox tables must still contain one row for its ID.
3. Select Start another order to create an intentional second purchase.
4. Use two browser sessions to compete for Last notebook. Only one order can allocate its final unit.
5. Enable the contradicted fixture and use a fresh browser session. The order must remain unwritten until the ceremony completes and policy allows it.

The [shared action contract](/integration/protected-actions) covers authenticated context, waiting, challenges, retries and database retention. The same browser client can protect [registration](/integration/account-registration) and other actions in your application.


## Related topics

- [Next.js and PostgreSQL](/integration/nextjs-postgres.md)
- [Prepare a session](/integration/prepare-session.md)
- [Account registration](/integration/account-registration.md)
- [Siteverify endpoint](/api/siteverify-endpoint.md)
- [Verdict endpoint](/api/verdict-endpoint.md)
