GET /v2/merchant/orders returns the authenticated merchant’s recent OrderV2
rows, JOINed against the Schema C repayment_history_attestations
collection for each row’s attestation block, plus a server-computed KPI
envelope and pagination. This endpoint is the data source for the merchant
Orders V2 page (Designer spec § 9) and the corresponding MCP
get_merchant_orders tool (Pillar 4).
Live on dev as of 2026-06-14; PROD ETA after next GTFU. Shipped via PR
#2104. Pillar 2
Trust Fabric (Schema C JOIN) × Pillar 4 MCP (server-computed KPIs) dual-purpose
surface — keep the read path scoped to the merchant rather than forking a
separate MCP-only endpoint.
GET /v2/merchant/orders
Authentication
Obtain a merchant JWT via
POST /merchant/admin/login — see
Authentication. Any ?merchantId= / ?shopId= query
parameter is silently dropped (OWASP A01:2021 IDOR mitigation; mirrors
MerchantInventoryAttestationsController and MerchantX402EarningsController).
Query parameters
Example
Response — 200 OK
Fields
Errors
Schema C JOIN
Eachrows[].attestation block comes from a JOIN against the Schema C
repayment_history_attestations collection — the on-chain rollup of order
repayment history that backs the Trust Fabric. Implementation details:
- Single bulk query. The JOIN is a single
$inquery against the sparseorderIdindex onrepayment_history_attestations. No N+1; the service collects everyorderIdfrom the Prisma fetch first, then issues one Schema C read for the page. - Newest-wins. If multiple Schema C rows reference the same
orderId(re-mint flows), the most recentlyrolledUpAtrow is returned. The collection retains history; the JOIN reads the latest. - Schema UID. Every returned block carries the Schema C UID
(
0xSCHEMACplaceholder above; the production value is registered on Base mainnet — see the EAS Schema v2 shipped 2026-06-11 note in the trust-fabric concept page). Clients can use this to disambiguate from Schemas A / B / D in a future mixed-schema view. - Missing coverage. Orders with no Schema C row land
attestation.status: "NOT_APPLICABLE"(orders that don’t qualify, e.g. refunded-before-settlement) or"PENDING"(qualifying orders not yet rolled up). Rows are never dropped fromrows[]because of a missing attestation — coverage is signaled via the per-rowstatusfield and aggregated intokpis.attestationCoveragePctBps.
KPI envelope
The KPI envelope is computed server-side so the FE never recomputes totals from the visible page (which would understate the window). All amounts are USD cents to keep aggregation float-safe;attestationCoveragePctBps
is basis points (0..10000) for the same reason — 25.00% ships as 2500,
no 0.25 floats on the wire.
totalOrdersInWindow— order rows matching the filter across the full window (not just the visible page).settledRevenueUsdCents—Σ grossUsdCentsfor rows whose FE bucket isSETTLED. Refunded / disputed rows are excluded.avgOrderValueUsdCents—settledRevenueUsdCents / count(SETTLED rows), integer division.0when no SETTLED rows in window.attestationCoveragePctBps—floor(10000 × count(attestation.status === "MINTED") / totalOrdersInWindow). Clamped to0..10000.0when the window is empty.
Per-section fail-open
The endpoint follows the Stripe Reliability + Shopify Platform fail-open discipline established by PR #1975 + #2042 — partial failures degrade per-section, never propagate as5xx:
The merchant never sees a partial-Orders-page error in the dashboard.
Notes
- 8→4 status mapping. The Prisma
OrderStatusenum has 8 values (CREATED,CONFIRMED,PROCESSING,SHIPPED,DELIVERED,REFUNDED,CANCELLED,DISPUTED); the FE bucket has 4 (SETTLED/PENDING/REFUNDED/DISPUTED). Mapping is centralized inMerchantOrdersService.mapStatusBucket():DELIVERED+SHIPPED+PROCESSING+CONFIRMED→SETTLEDREFUNDED+CANCELLED→REFUNDEDDISPUTED→DISPUTEDCREATEDand unmapped →PENDING(excluded fromSETTLEDrevenue; included intotalOrdersInWindow).
- Caching. The response carries
Cache-Control: private, max-age=60. Clients may see up to a 60s lag for fresh order events through CDN caches. - PSP filter is in-memory. Prisma’s Mongo provider does not
efficiently filter on a composite-type
payment.providerfield, so the PSP filter is applied in-memory after the Prisma fetch. Pagination math is over the filtered set. - Auth scope.
shopIdfromreq.user.shopIdonly. Any?merchantId=/?shopId=query parameter is silently dropped. A merchant cannot read another merchant’s orders through this endpoint. - Currency. All monetary fields are USD cents, integer — same
contract as
x402 Earnings (Merchant).
Divide by
100for major-unit display. - MCP twin. The same data feeds the
get_merchant_ordersMCP tool (Pillar 4). The wire shape is identical so a single OpenAPI schema generates both clients.
Related
- x402 Earnings (Merchant) — companion merchant-facing rollup of x402 settlement events.
- Billing Invoices (Merchant) — companion merchant-facing billing history (trailing 365 days).
- Brand Attestation Lifecycle — context on the Schema C → repayment-history → LenderRegistry attestation chain.
- Register Settlement Wallet — register where x402 micro-payments derived from these orders should route.