Idempotency
You can safely retry network failures without double-charging customers or double-creating orders.
Why it matters
Networks fail. Servers restart. Your retry logic shouldn't charge the customer twice. Restora 360 guards every mutation that involves money or external side-effects.
Order creation
POST /api/public/[tenantId]/orders is not idempotent by request — but it generates a fresh orderId every time, so a duplicate POST creates a duplicate order. To make it safe, either:
- Send an
Idempotency-Keyheader — supported, dedupes by header value for 24 hours. - Or use the payment-intent flow (POST
/api/public/[tenantId]/payment-intent) which atomically creates the order and the Stripe PaymentIntent in one call — Stripe's own idempotency then guards subsequent retries.
curl -X POST \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-7f1a-2025-05-28" \
-d @order.json \
https://api.restora360.com/api/public/luigi/ordersCommission ledger
Commission entries are keyed by (sourceInvoiceId, participantId) — replaying a Stripe webhook never double-pays a partner. The same invariant applies to:
- Designer + sales-agent commission entries (keyed by source-invoice id)
- Gift-card redemptions (keyed by orderId)
- Table-bill payments (one open bill per table at a time)
- Payout batches (keyed by batch id)
Webhook receiver
Every webhook event id is recorded; replay of the same id is a no-op 200. Stripe in particular retries failed deliveries for 3 days; Restora 360 absorbs the repeats safely.
When idempotency is **not** required
Read endpoints (GET) are inherently idempotent. DELETE is idempotent (deleting an already-deleted resource returns 200 / 204, not 404).