---
title: "Payments"
description: "Three ways to collect the money for an order, and what each does to the order."
---

> Documentation Index
> Fetch the complete documentation index at: https://developer.unipage.be/llms.txt
> Use this file to discover all available pages before exploring further.

# Payments

`paymentType` on [`POST /orders`](/storefront/api/orders/create/) decides who
collects the money.

| `paymentType` | Who collects the money | The order after `POST /orders` | `next.type` |
|---|---|---|---|
| `online` | Unipage, with the restaurant's own payment provider | `PENDING_PAYMENT`, unpaid | `payment` |
| `offline` | the restaurant, at pickup or on delivery | `PLACED`, unpaid | `confirmation` |
| `external` | you, with your own payment provider | `PLACED`, paid | `confirmation` |

`online` and `offline` are only accepted when the restaurant offers them: read
`payment.methods` from [`GET /store`](/storefront/api/store/retrieve/).
`external` is always accepted and is not listed there.

## Online: the restaurant's payment provider

1. **Place the order**

   Send `paymentType: "online"` and a `returnUrl` on one of your storefront's
   origins. `{orderId}` in it is replaced by the order id:

   ```json
   { "paymentType": "online", "returnUrl": "https://shop.example.com/order/{orderId}" }
   ```
2. **Send the shopper to the payment page**

   The response has `next.type: "payment"` and `next.url`: redirect the
   shopper's browser there.
3. **Read the outcome**

   After paying, the shopper comes back on `returnUrl` with `?status=success`
   or `?status=failed` (failed or cancelled). The query string is only a
   hint: read [`GET /orders/{id}`](/storefront/api/orders/retrieve/) from your
   server and use `isPaid` and `status`. With a [webhook](/storefront/webhooks/)
   you also get `order.paid` when the provider confirms.

Without `returnUrl` the shopper ends on the restaurant's own Unipage thank-you page.

## Offline: pay at the restaurant

The order is placed at once (`PLACED`), unpaid. The restaurant collects the money
at pickup or on delivery. Only possible when `payment.methods` contains
`offline`.

## External: you collect the money

Take the payment with your own provider first, then place the order with
`paymentType: "external"`. The order arrives `PLACED` and paid
(`isPaid: true`): the restaurant's till books it as a paid online order, like an
order from a delivery platform. Optionally tell Unipage where you took the
payment, for reconciliation:

```json
{
  "paymentType": "external",
  "payment": { "provider": "stripe", "reference": "pi_3Q8xYz" }
}
```

> **Only from your server**
>
> `external` places a paid order that nobody paid Unipage for. It needs the
> secret key, so it can only come from your server. Never let the browser
> decide the payment type: place the order with `external` only after your
> server has seen the payment succeed.

- Place the order after the payment succeeded. If the order is then refused
  (`SLOT_UNAVAILABLE`, `PRODUCT_UNAVAILABLE`, ...), refund the shopper.
- Refunds are yours: the money never passes through the restaurant's Unipage
  payouts, so Unipage cannot refund it.
- There is no `order.paid` [webhook](/storefront/webhooks/) for an `external`
  order: `order.created` already says `isPaid: true`.

Source: https://developer.unipage.be/storefront/payments/index.mdx
