Files
marketplaces/docs/backend/FRONTEND-API-SURFACE-COMPLETE.md
sdarbinyan bbf12cad33
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
docs: add §0 - auth + payment authorization was missing entirely
Direct question caught a real gap: "everything is there? payment auth?"
The census only grepped src/app/ - auth moved into the external
@marketplaces/auth package this session, and its HTTP calls were never
captured. Seven real endpoints were silently absent from a doc that called
itself "complete":

- 3 Telegram QR/session endpoints (POST/GET/DELETE .../users/sessions) -
  live today, customer and admin login share them, which is exactly why
  every admin endpoint must independently verify authorization server-side
- 4 ed25519 admin challenge/response endpoints - specified in
  BACKEND-HANDOFF.md §3 and the package's own auth-api.model.ts, but not
  built server-side. Client shows backend-unavailable until they exist.

Added §0.3 stating plainly what actually connects auth to payment: there is
no separate payment login. Checkout, order pricing (§20), and partner
credentials (§16) each ride on whichever of the two sessions above is
active, or on the partner API's own separate signed-request auth (§6 of
that contract - unrelated to Telegram/ed25519, already built, not a gap).
The real payment gap is §1 (QR/card creation and polling, undocumented
anywhere), not auth.

Counts corrected: 51->54 specified, 90->97 total. Added item 0 to the
action list, ahead of everything else: the ed25519 endpoints are the single
most serious open issue named anywhere in docs/backend/, and every other
item on the list assumes a working admin session to authorize against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:12:22 +04:00

28 KiB
Raw Blame History

Complete Frontend API Surface — Master Endpoint List

Generated 2026-08-18, updated same day after the frontend backlog (F1F65) closed, updated again same day to add §0 after a direct question ("everything is there? payment auth?") caught that the first pass only grepped src/app/ — auth moved into the external @marketplaces/auth package this session, and its own HTTP calls (§0) were missing from what this doc called "complete." Fixed by grepping node_modules/@marketplaces/auth/dist/ directly. Directly from source (every this.http.get/post/patch/put/delete call across src/app/core/, src/app/features/admin/, src/app/services/api.service.ts, and now the auth package). This is not a design document — it is a census: every endpoint this codebase currently calls or will call once its gateway swap goes live, in one place, cross-referenced against the contracts that already exist.

This is the final handoff doc for this pass. Frontend work is done except one item that genuinely cannot be finished without a live backend (§19). Everything else — every gateway, every model, every invariant — is written, tested, and pushed. What follows is everything backend needs to make it real.

Why this exists. The individual Phase/Track contracts in this directory each cover one domain well. Nothing until now listed the entire surface in one pass, so a backend dev building against these docs had no way to see what's fully specified, what's inferred-and-needs-confirmation, and what has no contract at all. This closes that gap.

Status legend

Status Meaning
Specified Exact shape exists in a Phase/Track contract doc. Build as written.
⚠️ Inferred Endpoint follows this codebase's own REST conventions (path pattern, verb) but no contract doc states it explicitly. Flagged in source with a comment at the call site. Confirm or correct before building — do not treat as final.
Undocumented Legacy endpoint, no contract anywhere, still called by api.service.ts. Will be replaced when the corresponding /api/v2 migration lands (Track N) — do not invest in these long-term, but they are live today.

0. Auth — lives in @marketplaces/auth, not this repo, and payment authorization runs through it

Two separate, real mechanisms. Both are called from the external package (node_modules/@marketplaces/auth/dist/), which is why §0 didn't exist in the first pass of this doc — that pass only grepped src/app/.

0.1 Telegram QR/session — Specified, live

Per BACKEND-HANDOFF.md §3 and PACKAGES-USAGE.md. Customer and admin login call the same endpoints — only client-side storage differs, which is exactly why every admin endpoint must independently verify authorization server-side (stated plainly in BACKEND-HANDOFF.md §3 as "the single most serious open issue in the system").

Method Path Purpose
POST {authApiUrl}/users/sessions create a session from a Telegram login
GET {authApiUrl}/users/sessions/{id} poll / check session status
DELETE {authApiUrl}/users/sessions/{id} log out

Expected response: { webSessionID, user: { userId, username, firstName, lastName }, status, expiresAt } — parsed permissively client-side (many key-name variants accepted), but a clean backend implementation should return exactly this shape.

0.2 Ed25519 admin challenge/response — specified, not built

Per BACKEND-HANDOFF.md §3 and the package's own ed25519/models/auth-api.model.ts. This is what backend-authorizes an admin session distinctly from a customer one, and it does not exist server-side yet — every request today shows a backend-unavailable screen once the client reaches for it, nothing is mocked.

Method Path
GET /api/admin/auth/challenge
POST /api/admin/auth/verify
POST /api/admin/auth/refresh
POST /api/admin/auth/logout

0.3 What this has to do with payment

There is no separate "payment login." Authorization for anything payment-adjacent — creating a checkout session, viewing GET /api/admin/v2/orders/{id}'s pricing breakdown (§20), touching a partner credential (§16) — rides on whichever of the two sessions above is active. The partner-provisioning API (§16) has its own, separate signed-request auth (§6 of that contract, public-key based, no session token at all) — that one is unrelated to Telegram/ed25519 and is not a gap, it's a different, already-built mechanism for a different caller (partners, not our own admins or customers).

The actual payment gap is §1 below, not auth: QR/card payment creation and status polling are real, live, and completely undocumented anywhere in docs/backend/.


1. Legacy surface (still called today, no /api/v2 contract)

These come from BACKEND-API-REFERENCE.md, not docs/backend/. Base URL is environment.localhostApiUrl / tenant-resolved; qrBaseUrl is a separate provider base for QR-specific calls.

Method Path Called from Status
GET /ping api.service.ts Undocumented — health check
GET /category api.service.ts, api-category.repository.ts Undocumented — full category tree
GET /category/{categoryID} api.service.ts Undocumented — one category + its items
GET /items/{itemID} api.service.ts Undocumented — single item detail
GET /searchitems api.service.ts Undocumented — search
GET /items/randomitems api.service.ts Undocumented — related/random items
POST /websession/{sessionId} api.service.ts Undocumented — sync cart to a Telegram web session
POST /items/{itemID}/callback api.service.ts Undocumented — "call me back" request
POST /items/{itemID}/questiion api.service.ts Undocumented — product Q&A (note: questiion typo is load-bearing, do not silently "fix" without checking the live backend uses the same typo)
POST /items/{itemID}/notify-me api.service.ts Undocumented — back-in-stock subscription
POST /purchase-email api.service.ts Undocumented — post-purchase email collection
POST {qrBaseUrl}/qr api.service.ts Undocumented — direct QR payment creation
POST /cart api.service.ts Undocumented — legacy payment creation, client-sent amount (superseded by §2 below for new checkout flow; still live for any caller not yet migrated)
GET {qrBaseUrl}/qr/dynamic/{partnerId}/{qrId} api.service.ts Undocumented — QR payment status poll
GET {qrBaseUrl}/card/{partnerId}/{orderId} api.service.ts Undocumented — card payment status poll
POST /orders api.service.ts Undocumented — records a paid cart as a backoffice order, fire-and-forget

Recommendation: these 15 need their own contract doc if they are staying, or a deprecation timeline if /api/v2/storefront/* replaces them. Right now they are simply undocumented and live — the single biggest gap in docs/backend/.


2. Storefront checkout & cart — Specified

Contract: PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §5.2, PHASE-6-CART-CHECKOUT-CONTRACT.md §3, §5.

Method Path Called from
GET /api/v2/storefront/cart server-cart-api.gateway.ts
POST /api/v2/storefront/cart/lines server-cart-api.gateway.ts
PATCH /api/v2/storefront/cart/lines/{lineId} server-cart-api.gateway.ts
DELETE /api/v2/storefront/cart/lines/{lineId} server-cart-api.gateway.ts
POST /api/v2/storefront/checkout server-cart-api.gateway.ts, api.service.ts (two different callers, same contract)
POST /api/v2/storefront/payments/intents api.service.ts

3. Pricing — Specified

Contract: PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §3.1.

Method Path Called from
GET /api/v2/pricing/fx-quote?base=&quote= fx-quote-api.gateway.ts

4. Identity & permissions — Specified

Contracts: PHASE-8-IDENTITY-MESSAGING-CONTRACT.md §2, TRACK-S-SECURITY-RBAC-CONTRACT.md §2.

Method Path Called from
GET /api/identity/v1/vk/authorize vk-id-api.gateway.ts
POST /api/identity/v1/vk/callback vk-id-api.gateway.ts
GET /api/identity/v1/session/permissions permission-api.gateway.ts

5. Team / RBAC — mixed

Contract: TRACK-S-SECURITY-RBAC-CONTRACT.md §8.

Method Path Called from Status
GET /api/admin/v2/audit permission-api.gateway.ts, admin-users-api.gateway.ts?actor= Specified
POST /api/admin/v2/team/invite admin-users-api.gateway.ts Specified
GET /api/admin/v2/team?marketplaceId= admin-users-api.gateway.ts Specified
PATCH /api/admin/v2/team/{userId} admin-users-api.gateway.ts Specified
DELETE /api/admin/v2/team/{userId} (interface exists, not yet called) Specified
GET /api/admin/v2/team/roles admin-users-api.gateway.ts ⚠️ Inferred
GET /api/admin/v2/team/invitations admin-users-api.gateway.ts ⚠️ Inferred
GET /api/admin/v2/team/{userId}/sessions admin-users-api.gateway.ts ⚠️ Inferred
PATCH /api/admin/v2/team/{userId}/status admin-users-api.gateway.ts ⚠️ Inferred
DELETE /api/admin/v2/team/invitations/{id} admin-users-api.gateway.ts ⚠️ Inferred
DELETE /api/admin/v2/team/sessions/{sessionId} admin-users-api.gateway.ts ⚠️ Inferred

6. Orders & notifications — Specified

Contract: PHASE-2-ORDERS-NOTIFICATIONS-CONTRACT.md.

Method Path Called from
GET /api/admin/v2/orders?marketplaceId=&status=&source=&page=&pageSize= admin-orders-api.gateway.ts
GET /api/admin/v2/orders/{id} admin-orders-api.gateway.ts
PATCH /api/admin/v2/orders/{id}/status admin-orders-api.gateway.ts
POST /api/admin/v2/orders/{id}/refund-request admin-orders-api.gateway.ts (note: gateway calls this refund-request; interface method is named requestRefund — same endpoint)
POST /api/admin/v2/orders/{id}/notes admin-orders-api.gateway.ts
POST /api/admin/v2/orders/{id}/archive admin-orders-api.gateway.ts
POST /api/admin/v2/orders/{id}/restore admin-orders-api.gateway.ts
DELETE /api/admin/v2/orders/{id} admin-orders-api.gateway.ts
GET /api/admin/v2/notifications?marketplaceId=&unreadOnly=&eventType= admin-notifications-api.gateway.ts
PATCH /api/admin/v2/notifications/{id}/read admin-notifications-api.gateway.ts
PATCH /api/admin/v2/notifications/read-all admin-notifications-api.gateway.ts

7. Catalog / offers — Specified + ⚠️ Inferred

Contract: PHASE-3-CATALOG-OFFER-FULFILLMENT-CONTRACT.md §7.

Method Path Called from Status
GET /api/admin/v2/products?marketplaceId=&status=&search=&page=&pageSize= admin-products-api.gateway.ts Specified
GET /api/admin/v2/products/{id} admin-products-api.gateway.ts Specified
POST /api/admin/v2/products admin-products-api.gateway.ts Specified
PATCH /api/admin/v2/products/{id} admin-products-api.gateway.ts Specified
GET /api/admin/v2/offers?productId=&sellerId=&status= offer-api.gateway.ts Specified
POST /api/admin/v2/offers/{id}/publish offer-api.gateway.ts Specified — 422 + details[] on executability failure
GET /api/admin/v2/offers/lookup?sku=&sellerSku=&externalId= offer-api.gateway.ts Specified
GET /api/admin/v2/products/categories admin-products-api.gateway.ts ⚠️ Inferred
DELETE /api/admin/v2/products/{id} admin-products-api.gateway.ts ⚠️ Inferred
POST /api/admin/v2/products/{id}/duplicate admin-products-api.gateway.ts ⚠️ Inferred
POST /api/admin/v2/products/{id}/archive admin-products-api.gateway.ts ⚠️ Inferred
POST /api/admin/v2/products/{id}/restore admin-products-api.gateway.ts ⚠️ Inferred
GET /api/admin/v2/offers/{offerId}/inventory offer-api.gateway.ts ⚠️ Inferred

8. Categories — Specified (pre-existing, F29 done before this session)

Method Path Called from
GET {baseUrl} (categories collection) admin-categories-api.gateway.ts
GET {baseUrl}/{id} admin-categories-api.gateway.ts
POST {baseUrl} admin-categories-api.gateway.ts
PUT {baseUrl}/{id} admin-categories-api.gateway.ts
DELETE {baseUrl}/{id} admin-categories-api.gateway.ts
POST {baseUrl}/{id}/restore admin-categories-api.gateway.ts
GET {baseUrl}/slug-taken admin-categories-api.gateway.ts

9. Seller portal — mixed

Contract: PHASE-5-SELLER-PORTAL-CONTRACT.md §3.

Method Path Called from Status
GET /api/seller/v1/finance/settlements (contract-only, no current caller) Specified
GET /api/admin/v2/sellers seller-api.gateway.ts ⚠️ Inferred — contract only specifies the caller's own GET /api/seller/v1/profile, not an admin list-all
GET /api/admin/v2/sellers/{sellerId}/team seller-api.gateway.ts ⚠️ Inferred — contract's GET /api/seller/v1/team is session-scoped, not parameterized

10. Payments, refunds, reconciliation, settlements — Specified

Contract: PHASE-7-PAYMENTS-RECONCILIATION-CONTRACT.md.

Method Path Called from
GET /api/admin/v2/orders/{orderId}/refunds finance-api.gateway.ts
GET /api/admin/v2/reconciliation/queue finance-api.gateway.ts
POST /api/admin/v2/reconciliation/{id}/resolve finance-api.gateway.ts
GET /api/admin/v2/finance/settlements?sellerId= finance-api.gateway.ts

11. Tenant registry — mixed

Contract: PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md.

Method Path Called from Status
GET /api/admin/v2/marketplaces/{id}/lifecycle marketplace-api.gateway.ts Specified
GET /api/admin/v2/marketplaces (list) marketplace-api.gateway.ts ⚠️ Inferred — contract specifies POST for creation, not the list GET
GET /api/admin/v2/marketplaces/{id}/domains marketplace-api.gateway.ts ⚠️ Inferred

12. Connector framework — mixed

Contract: PHASE-4-CONNECTOR-FRAMEWORK-CONTRACT.md §7-8.

Method Path Called from Status
GET /api/admin/v2/integrations connector-api.gateway.ts Specified
PATCH /api/admin/v2/integrations/{id} connector-api.gateway.ts (pause/resume via status field) Specified
GET /api/admin/v2/integrations/{connectorId}/dead-letter connector-api.gateway.ts ⚠️ Inferred — contract specifies replay, not the list
POST /api/admin/v2/integrations/{connectorId}/dead-letter/{id}/replay connector-api.gateway.ts Specified — path corrected 2026-08-18; the gateway initially omitted connectorId, caught while writing this doc, fixed in the same pass

13. Content modules (Gorbushka-class) — ⚠️ Mostly inferred

Contract: PHASE-10-CONTENT-MODULES-CONTRACT.md §2.

Method Path Called from Status
POST /api/admin/v2/content/rent-listings/{id}/leads mall-content-api.gateway.ts Specified
GET /api/admin/v2/content/shops mall-content-api.gateway.ts ⚠️ Inferred
GET /api/admin/v2/content/shop-categories mall-content-api.gateway.ts ⚠️ Inferred
GET /api/admin/v2/content/floors mall-content-api.gateway.ts ⚠️ Inferred
GET /api/admin/v2/content/floors/{floorId}/pins mall-content-api.gateway.ts ⚠️ Inferred
GET /api/admin/v2/content/rent-listings mall-content-api.gateway.ts ⚠️ Inferred

14. Analytics — Specified

Contract: TRACK-A-ANALYTICS-CONTRACT.md §1.

Method Path Called from
POST /api/v2/storefront/analytics/events analytics-api.gateway.ts

15. Transactions, monitoring, moderation — No contract doc exists

These three domains have gateways calling /api/admin/v2/{resource} by convention only. No Phase/Track doc covers any of them.

Method Path Called from
GET /api/admin/v2/transactions admin-transactions-api.gateway.ts
POST /api/admin/v2/transactions/{id}/retry admin-transactions-api.gateway.ts
PATCH /api/admin/v2/transactions/{id} admin-transactions-api.gateway.ts
GET /api/admin/v2/monitoring/events admin-monitoring-api.gateway.ts
GET /api/admin/v2/monitoring/queues admin-monitoring-api.gateway.ts
GET /api/admin/v2/monitoring/webhooks admin-monitoring-api.gateway.ts
GET /api/admin/v2/moderation/reviews admin-moderation-api.gateway.ts
GET /api/admin/v2/moderation/reviews/{id} admin-moderation-api.gateway.ts
PATCH /api/admin/v2/moderation/reviews/{id} admin-moderation-api.gateway.ts (status/visible/pinned/featured — 4 different PATCH bodies, same endpoint)
POST /api/admin/v2/moderation/reviews/{id}/notes admin-moderation-api.gateway.ts
DELETE /api/admin/v2/moderation/reviews/{id} admin-moderation-api.gateway.ts
GET /api/admin/v2/moderation/reports admin-moderation-api.gateway.ts
PATCH /api/admin/v2/moderation/reports/{id} admin-moderation-api.gateway.ts
GET /api/admin/v2/dashboard/metrics admin-dashboard-metrics-api.gateway.ts

Recommendation: these are the highest-priority gap. Three full admin domains with real UI and real gateways, zero backend contract. Whoever picks up Phase 5/7 next should write these as proper contract docs — the endpoint shapes above are a starting point, not a spec.

16. Partner provisioning API — Specified

Contract: PARTNER-PROVISIONING-API-CONTRACT.md §4, §6. This is the one domain where the frontend gateway was built from the contract, not the other way around — no drift to reconcile.

Method Path Called from
GET /api/partner/v1/companies/{companyId}/hierarchy?environment= partner-hierarchy-api.gateway.ts
GET /api/partner/v1/nodes/{nodeId} partner-hierarchy-api.gateway.ts
GET /api/partner/v1/nodes/lookup?externalReference=&environment= partner-hierarchy-api.gateway.ts
POST /api/partner/v1/companies/{companyId}/projects partner-hierarchy-api.gateway.ts
POST /api/partner/v1/projects/{projectId}/stores partner-hierarchy-api.gateway.ts
POST /api/partner/v1/stores/{storeId}/payment-points partner-hierarchy-api.gateway.ts
PATCH /api/partner/v1/nodes/{nodeId}/status partner-hierarchy-api.gateway.ts
POST /api/partner/v1/nodes/{nodeId}/disable partner-hierarchy-api.gateway.ts
GET /api/partner/v1/credentials?companyId= partner-hierarchy-api.gateway.ts
POST /api/partner/v1/credentials partner-hierarchy-api.gateway.ts
POST /api/partner/v1/credentials/{keyId}/rotate partner-hierarchy-api.gateway.ts
DELETE /api/partner/v1/credentials/{keyId} partner-hierarchy-api.gateway.ts

17. Backoffice data & bootstrap — Specified elsewhere (not a Phase/Track doc, but stable)

Method Path Called from
GET /api/backoffice/products api-backoffice-data.provider.ts
GET /api/backoffice/categories api-backoffice-data.provider.ts
GET (tenant bootstrap URL) api-bootstrap.provider.ts — see BACKEND-HANDOFF.md §1a

18. Marketplace publish/revision model — Specified

Contract: PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md §5. Frontend core built (marketplace-revision-*.gateway.ts), not yet wired into the project editor's UI — see §20.

Method Path Called from
POST /api/admin/v2/marketplaces/{id}/revisions marketplace-revision-api.gateway.ts — create draft
POST /api/admin/v2/marketplaces/{id}/revisions/{revId}/validate marketplace-revision-api.gateway.ts
POST /api/admin/v2/marketplaces/{id}/revisions/{revId}/publish marketplace-revision-api.gateway.ts
POST /api/admin/v2/marketplaces/{id}/revisions/{revId}/rollback marketplace-revision-api.gateway.ts — creates a NEW revision, never mutates the old one

One real ambiguity in §5 itself, flagged for confirmation, not guessed silently: the pipeline is described as 4 stages (draft → validated → preview → publish) but only 3 write endpoints exist (validate/publish/rollback) — there is no dedicated "move to preview" call. The frontend model assumes POST .../validate moves a revision straight to preview (the state publish requires), treating validated as a value the caller may never observe. Confirm this is correct before implementing — if the real response returns status: 'validated' and requires a separate step to reach preview, the frontend model and this doc both need updating.

19. RoutingContext on payments — carried through, not yet backend-verified

Contract: PARTNER-PROVISIONING-API-CONTRACT.md §7, PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §6.5. Not a separate endpoint — a field addition backend needs to populate on existing responses:

routing?: {
  companyId: string;
  routingPath: string[];
  leafNodeId: string;
  environment: 'TEST' | 'LIVE';
  merchantReference: string;
  providerPaymentId: string;
}

Frontend added this as an optional field on AdminOrder (admin-order.model.ts) and renders it on the order detail page when present. Nothing breaks if it's absent — but nothing shows the payment-point attribution either until backend populates it on GET /api/admin/v2/orders/{id}.

20. Order pricing breakdown — same pattern, different fields

Contract: PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §5.3. Optional fields added to AdminOrderItem and AdminOrder:

// per line
unitPriceMinor?: number;
lineTotalMinor?: number;
priceSnapshotId?: string;
discountMinor?: number;

// per order
fxQuoteId?: string;
deliveryMinor?: number;

Frontend renders a "total formula" panel on the order detail page (order-total-formula.component.ts) reconstructing total = sum(unitPrice*qty) - discounts + delivery, with the FX quote used. It refuses to show a partial breakdown — every line must carry unitPriceMinor or the panel says "not available" instead of a number that's silently wrong. Populate these fields on GET /api/admin/v2/orders/{id} to make it real; until then it correctly shows nothing.

21. Dashboard metrics — 8 new optional fields, no shape confirmed

Contract intent: PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md §7's target metric list — no contract doc defines GET /api/admin/v2/dashboard/metrics's response shape (§15 already flagged this endpoint has no spec at all). Frontend added these as optional fields on AdminDashboardMetrics, each rendering 'unknown' (not a fabricated 'healthy') while absent:

gmvMinor?: number;
currency?: string;
paidOrdersCount?: number;
conversionRate?: number;          // 0-1, not a percentage
paymentFailureRate?: number;      // 0-1
moderationQueueCount?: number;
lowStockCount?: number;
unmatchedEventsCount?: number;
integrationHealthyCount?: number;
integrationTotalCount?: number;

This is a genuine ask, not a confirmed contract — §15's recommendation to write a real spec for this endpoint still stands. These field names are what the frontend already expects; change them here first if backend needs different ones.

22. Idempotency — frontend now guards, backend enforcement is still required

The frontend added a client-side guard against double-submitting checkout (a real bug: double-clicking used to fire two POST /api/v2/storefront/checkout calls — fixed in cart.component.ts, checkoutInFlight signal). This does not replace backend idempotency and was never meant to. It closes one specific UI race; it does nothing for a retried request from a flaky network, a backgrounded tab resuming, or an actual duplicate webhook delivery. Contract requirements are unchanged and still required:

  • PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §6.3 — webhook idempotency key = provider + providerEventId
  • PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §6.4 — order creation idempotency key = checkoutSessionId
  • PARTNER-PROVISIONING-API-CONTRACT.md §5 — Idempotency-Key header semantics for all partner-API creates

Summary counts

Status Count
Specified 54
⚠️ Inferred (needs confirmation) 24
Undocumented (legacy) 15
Total distinct endpoints called 97

(§0's 3 Telegram endpoints count as Specified+live; its 4 ed25519 endpoints count as Specified+not-built — both are real, named endpoints with a known shape, distinct from §1's "no contract exists anywhere" undocumented status.)

Plus 3 response-shape additions (§1921) on existing endpoints — not new endpoints, new optional fields on responses those endpoints already return.

What backend needs to do with this

  1. §0.2 first, ahead of everything else on this list. The 4 ed25519 admin auth endpoints are the single most serious open issue named anywhere in docs/backend/ (BACKEND-HANDOFF.md §3's own words). Every other item below assumes an admin session exists to authorize the request — that session mechanism does not exist server-side yet.
  2. Build the rows as written — they match an existing contract doc exactly. This includes §18's 4 revision endpoints, pending confirmation on the validated/preview ambiguity called out there.
  3. Confirm or correct every ⚠️ row — each one has a comment at its call site in source explaining the inference. Search the codebase for Inferred to find all 24 in place, with the reasoning right next to the code.
  4. Populate the 3 optional field sets (§1921) on the endpoints that already exist — routing and pricing-breakdown fields on GET /api/admin/v2/orders/{id}, the 8 metric fields on GET /api/admin/v2/dashboard/metrics. Nothing on the frontend breaks while these are absent; nothing shows the real data either.
  5. Write a contract for §15 (transactions, monitoring, moderation) — real UI, real gateways, zero spec. Highest-priority gap in this whole list.
  6. Decide the fate of §1 — 15 legacy endpoints with no contract at all, still live. Either document them as a stable, permanent surface, or set a Track N migration date.
  7. Enforce idempotency server-side regardless of §22 — the frontend's double-click guard is a UI nicety, not a substitute for Idempotency-Key/providerEventId dedup.

One item that stays blocked until a real backend exists

The frontend backlog (F1F65, tracked this session) is complete except F60: the full acceptance-path E2E — seller → catalog → storefront → cart → checkout → payment → order → notification → fulfillment, in one test, against real infrastructure. Every other item is written, unit-tested, E2E-covered where an E2E test could prove something real, and pushed. This one cannot be honestly finished by mocking harder — it needs an actual backend to run against. Once even a minimal version of Phases 14 is live, this is the next thing to build (docs/PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md Track Q, Q3).