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

# Accept Payments

> Use the protected Crave payment session selected for the restaurant.

Crave selects the restaurant's connected payment provider server-side. Square is selected whenever it is connected; Stripe is used only where Square is disconnected.

## Create a payment session

```ts theme={null}
const payment = await storefront.checkout.createPaymentSession(
  locationId,
  cartId,
  { idempotencyKey: crypto.randomUUID() },
);
```

The SDK sends the cart capability, current revision, and idempotency key. A raw REST request must send the same headers:

```bash theme={null}
curl -X POST "https://api.craveup.com/api/v1/storefront/locations/loc_123/carts/cart_456/payment-session" \
  -H "X-Cart-Token: $CART_ACCESS_TOKEN" \
  -H 'If-Match: "cart-4"' \
  -H "Idempotency-Key: payment_01"
```

If `payment.provider` is `SQUARE`, tokenize with Square Web Payments and send the token to `checkout.confirmPayment`. If it is `STRIPE`, confirm its client secret with Stripe Elements.

## Confirm a Stripe session with Stripe Elements

```tsx theme={null}
import {
  PaymentElement,
  useElements,
  useStripe,
} from "@stripe/react-stripe-js";

export function PaymentForm() {
  const stripe = useStripe();
  const elements = useElements();

  async function submit(event: React.FormEvent) {
    event.preventDefault();
    if (!stripe || !elements) return;

    const { error } = await stripe.confirmPayment({
      elements,
      confirmParams: {
        return_url: `${window.location.origin}/order/confirmation`,
      },
    });

    if (error) showPaymentError(error.message);
  }

  return (
    <form onSubmit={submit}>
      <PaymentElement />
      <button>Pay now</button>
    </form>
  );
}
```

Use Stripe publishable configuration in the client. Stripe secret keys remain on Crave-managed services. Never collect or log raw card numbers.

After Stripe returns, poll `storefront.checkout.getOrderResult(locationId, cartId)`. Treat only `completed` as success; `payment_pending` and `order_pending` are retryable states, while `failed` is terminal.

<CardGroup cols={2}>
  <Card title="Checkout Flow" icon="credit-card" href="/guides/checkout-flow">
    See the complete checkout state machine.
  </Card>

  <Card title="Order Tracking" icon="location-dot" href="/guides/order-tracking">
    Poll the order result and load protected receipts.
  </Card>
</CardGroup>
