Docs detail

API Ordering Flow

End-to-end menu to order-status flow with card and crypto curl snippets.

Owner: genesis-api

This page documents the canonical order flow:

  1. GET /v1/menu
  2. POST /v1/orders/quote
  3. POST /v1/orders/confirm
  4. GET /v1/orders/{id}

Core contract references:

Base URL

Development:

export BASE_URL="http://localhost:3000"

1) Fetch menu

curl -sS "$BASE_URL/v1/menu"

2) Create quote

curl -sS -X POST "$BASE_URL/v1/orders/quote" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "sku": "PZ-MAR", "qty": 1 },
      { "sku": "DR-COL", "qty": 1 }
    ],
    "fulfillment": { "type": "pickup" },
    "contact": {
      "name": "API Flow Test",
      "phone": "+33600000000",
      "email": "api-flow@example.com"
    }
  }'

Save values from quote response:

  • quoteId
  • quoteHash
  • totalCents
  • currency
  • expiresAt
  • merchantId
  • merchantAddress

3A) Confirm flow (card branch)

curl -sS -X POST "$BASE_URL/v1/orders/confirm" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteId": "YOUR_QUOTE_ID",
    "paymentMethod": "card",
    "assertions": {
      "expectedQuoteHash": "sha256:YOUR_QUOTE_HASH",
      "expectedTotalCents": 1200,
      "maxTotalCents": 1200,
      "expectedCurrency": "EUR",
      "expectedPaymentMethod": "card",
      "expectedExpiresAt": "2026-03-03T18:30:00Z",
      "expectedMerchantId": "au-comptoir-a-patons",
      "expectedMerchantAddress": "111 Rue Sebastien Gryphe, 69007 Lyon, France"
    }
  }'

Expected response: paymentIntentId, clientSecret, and amount details.

3B) Confirm flow (crypto branch)

First call (expect 402 with payment requirements):

curl -i -sS -X POST "$BASE_URL/v1/orders/confirm" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteId": "YOUR_QUOTE_ID",
    "paymentMethod": "crypto"
  }'

From the 402 body, capture paymentRequestId and paymentRequirements.

Second call:

  • local mock adapter: reuse paymentRequestId
  • live Coinbase/x402 adapter: build a real payment proof from paymentRequirements

The proof can be sent in the legacy PAYMENT-SIGNATURE header or the JSON paymentSignature field.

Example header form:

curl -sS -X POST "$BASE_URL/v1/orders/confirm" \
  -H "Content-Type: application/json" \
  -H "PAYMENT-SIGNATURE: YOUR_PAYMENT_REQUEST_ID" \
  -d '{
    "quoteId": "YOUR_QUOTE_ID",
    "paymentMethod": "crypto"
  }'

Expected response: orderId with paid status.

Recovery branches

When confirm fails, use the error code to choose the smallest safe retry path:

  • ASSERTION_FAILED_*: quote state drifted; recreate the quote and reuse the new quoteHash, amount, expiry, and merchant assertions.
  • PAYMENT_INVALID with details.reason = invalid_signature: rebuild the proof payload instead of replaying the same broken bytes.
  • PAYMENT_INVALID with details.reason = expired: create a fresh quote before retrying payment.
  • PAYMENT_INVALID with details.reason = wrong_network: switch the wallet back to Base (eip155:8453) before retrying.
  • PAYMENT_INVALID with details.reason = insufficient_funds: top up the wallet before retrying; details.requiredAtomic is the exact minimum.

4) Fetch order status

curl -sS "$BASE_URL/v1/orders/YOUR_ORDER_ID"

Notes

  • Quote expiry matters: if expired, create a new quote.
  • For crypto, wallet setup is available at GET /v1/wallet-setup.
  • Always use confirm-time assertions in agentic/automated flows to prevent silent divergence.
  • For merchant-configurable deployments, read the actual rail from merchant bootstrap and quote responses instead of assuming one global payment method.
  • Prefer the on-domain AGENTS and OpenAPI assets above when linking builders into the contract surface.