Payments & Money APIs · Webhooks, Orchestration & Recurring Payments

Orchestrating Orders, Inventory & Payments

Outbox, sagas and timeouts across order, stock and payment services.

Checkout touches several systems: reserve inventory, create/confirm payment, create order, send confirmation, fulfil. Without distributed transactions, use a saga: each step has a compensation (release stock, void/refund payment), state is persisted, and timeouts trigger compensations (e.g. reservation expires after 15 minutes if payment isn't confirmed). Publish events with the transactional outbox so "order paid" is never lost or emitted for a rolled-back transaction.

Checkout saga

Step Action Compensation
1. Reserve stock Hold items with TTL Release reservation
2. Authorize/charge PaymentIntent confirm Void (if authorized) / refund (if captured)
3. Confirm order State → paid, outbox event Cancel order
4. Fulfil Pick, pack, ship Return flow
Timeout No payment in 15 min Release stock, cancel order

Python (outbox in the same transaction)

async def mark_paid(order_id: str, event_id: str):
    async with db.transaction():
        if not await transition(db, order_id, "paid", event_id=event_id):
            return
        await db.execute(
            "INSERT INTO outbox(id, topic, key, payload) VALUES ($1, 'orders.paid', $2, $3)",
            uuid7(), order_id, json.dumps({"order_id": order_id, "event_id": event_id}))
    # a relay publishes outbox rows to the broker; consumers (fulfilment, email) dedupe by id

Common pitfalls

  • Charging before checking stock availability (refund churn).
  • Emitting events outside the DB transaction.
  • Reservations that never expire.

Key points

  • Saga with compensations
  • Outbox for reliable events
  • Timeouts on reservations and payments

Further reading: microservices.io: Saga

Practice questions

What compensation applies if stock can't be allocated after a payment was authorized?

Answer

Void the authorization (or refund if already captured), cancel the order and notify the customer.

Why use a transactional outbox for 'order paid' events?

Answer

It writes the event in the same DB transaction as the state change, so the event is published if and only if the change committed.

Open in the app to mark lessons complete, take notes and track your progress.