Merchant orders
List orders, view order detail, and check a gift card's remaining balance.
Merchant orders are the BFF behind the dashboard's Sales page: order lifecycle, payment status, and reference search, plus per-gift-card balance lookups.
Different auth and error shape from other sub-areas
These three endpoints check the session and merchant permission inline
rather than via the shared requireBffMerchantAuth helper used by POS and
Offers, and their error responses use a bare string
({ "ok": false, "error": "..." }) instead of the
{ "ok": false, "error": { "message": "...", ... } } envelope used
elsewhere. The underlying permission model (portal.orders) is the same.
List orders
GET /api/bff/merchant-ordersRequires the portal.orders permission. If the session user has no
associated merchant, this returns an empty result set with a 200 rather than
an error.
Query parameters
| Param | Type | Default | Notes |
|---|---|---|---|
page | number | 1 | Coerced to at least 1. |
pageSize | number | 20 | Coerced to at least 1, capped at 50. |
status | string | none | Must be a valid OrderStatus value, otherwise ignored. |
paymentStatus | string | none | Must be a valid PaymentStatus value, otherwise ignored. |
q | string | none | Free-text search (max 120 chars), matched case-insensitively against order ID, buyer email, buyer name, payment transaction ID, and gr4vy transaction ID. |
OrderStatus values: PENDING_PAYMENT, PAYMENT_CAPTURED_PENDING_FRAUD_REVIEW,
PAYMENT_CAPTURE_SUCCEEDED, PAYMENT_AUTH_SUCCEEDED,
PAYMENT_CAPTURE_PENDING_REVIEW, PAYMENT_FAILED, PAID, FAILED,
ISSUE_FAILED, COMPLETED, CANCELLED, REFUNDED.
PaymentStatus values: PAYMENT_CREATED, PAYMENT_AUTHORIZED,
PAYMENT_CAPTURE_SUCCEEDED, PAYMENT_CAPTURE_FAILED, PAYMENT_FAILED.
Response
{
"ok": true,
"data": {
"orders": [
{
"id": "...",
"createdAt": "2026-06-26T00:00:00.000Z",
"status": "COMPLETED",
"paymentStatus": "PAYMENT_CAPTURE_SUCCEEDED",
"fulfilmentStatus": "FULFILMENT_FULFILLED",
"currency": "EUR",
"totalAmountMinor": 2500,
"buyerEmail": "[email protected]",
"buyerName": "...",
"paymentTransactionId": "...",
"gr4vyTransactionId": "...",
"_count": { "items": 1 }
}
],
"total": 1,
"page": 1,
"pageSize": 20
}
}Orders are ordered newest first.
Errors
| Status | Cause |
|---|---|
| 401 | No session. |
| 403 | Session user's role lacks the portal.orders permission. |
| 500 | Unexpected internal error. |
Get an order
GET /api/bff/merchant-orders/{orderId}Requires the portal.orders permission. Used for the Sales detail view.
Path parameters
| Param | Required |
|---|---|
orderId | yes |
Response
{
"ok": true,
"data": {
"id": "...",
"createdAt": "2026-06-26T00:00:00.000Z",
"updatedAt": "2026-06-26T00:00:00.000Z",
"status": "COMPLETED",
"paymentStatus": "PAYMENT_CAPTURE_SUCCEEDED",
"fulfilmentStatus": "FULFILMENT_FULFILLED",
"currency": "EUR",
"totalAmountMinor": 2500,
"buyerEmail": "[email protected]",
"buyerName": "...",
"recipientEmail": "...",
"recipientName": "...",
"deliveryType": "EMAIL",
"giftCards": [
{
"id": "...",
"qrCode": "...",
"status": "ISSUED",
"valueMinor": 2500,
"currency": "EUR"
}
],
"items": [
{
"offerName": "...",
"quantity": 1,
"amountMinor": 2500,
"currency": "EUR"
}
]
}
}giftCards[].status is one of PENDING, ISSUED, FAILED, CANCELLED.
Errors
| Status | Cause |
|---|---|
| 401 | No session. |
| 404 | Session user has no associated merchant, missing orderId, or no order matches orderId for this merchant. |
| 403 | Session user's role lacks the portal.orders permission. |
| 500 | Unexpected internal error. |
Get a gift card's remaining balance
GET /api/bff/merchant-orders/{orderId}/gift-cards/{giftCardId}/balanceRequires the portal.orders permission. Looks up the gift card by ID and
order ID locally, then queries the card network for its current balance
using the card's QR code.
Path parameters
| Param | Required |
|---|---|
orderId | yes |
giftCardId | yes |
Response
{
"ok": true,
"data": {
"giftCardId": "...",
"qrCode": "...",
"remainingValueMinor": 1500,
"currency": "EUR",
"upstreamStatus": "..."
}
}remainingValueMinor is derived by converting the upstream valueRemains
(a decimal amount) to integer minor units; it is null if the upstream
response doesn't include a usable value. upstreamStatus is the raw
giftCardStatus string from the card network, not the portal's
GiftCardStatus enum.
Errors
| Status | Cause |
|---|---|
| 401 | No session. |
| 404 | Session user has no associated merchant, or no gift card matches giftCardId + orderId for this merchant. |
| 403 | Session user's role lacks the portal.orders permission. |
| 400 | Missing orderId/giftCardId path parameter, or the matched gift card has no QR code on record. |
| 500 | Unexpected internal error, including an upstream lookup failure. |