Growth API route carve-up inventory; 46 routes audited, 2 stay in Growth, 44 are handoff candidates
Why
The Growth repo's src/app/api/ accumulated cross-domain API routes over time, before the post-Lifecycles ownership map (coordination/domains/) settled. As a one-time hygiene pass before the Postgres pilot work picks up speed, Growth audited every route and bucketed it by the domain that owns the underlying Airtable table.
The bucketing is mechanical. The Airtable schema config (growth/src/config/airtable-schema.ts) splits into two bases. core.tables carries Growth's three tables (leadIntakes, leadAttributions, campaigns). operations.tables carries the 29 tables that belong to Platform, Delivery, Revenue, or jointly. Each route in src/app/api/ is a thin shim over a @/modules/<name> module; each module reads from one or both bases; the base picks the destination domain.
This memo lays out the inventory and proposes the handoff. Per-domain handoff memos will follow as in-reply-to this one as each move is sequenced.
What
46 route handlers in growth/src/app/api/ today. By destination:
Growth, keep, initiative scope
The two routes the 2026-05-23 pilot-scope memo names. They stay in this repo and move through the Postgres cutover.
| Route | Module | Airtable table |
|---|---|---|
| POST /api/lead-intakes | lead-intakes | core.leadIntakes |
| GET, POST /api/webhooks/meta | app/webhooks/meta (re-exported) | core.leadIntakes (writes via the same backing path) |
Sales, propose handoff (1 route)
Brand-new, no Airtable predecessor. Per 2026-05-09-sales-q2-airtable-sunset-scoping: "Quo integration not in scope because no Airtable predecessor exists." Quo is Sales' partner-platform contact intake; small and uncontested, the textbook quiet-relocate case.
| Route | Module | Notes |
|---|---|---|
| POST /api/quo-contacts | quo-contacts | No Airtable backing; Sales' Quo integration. |
Platform, propose handoff (5 routes)
Cross-cutting infrastructure: config rail, identity-externals reverse-lookup, eventing-rail observability backfills.
| Route | Module | Airtable tables |
|---|---|---|
| POST /api/client-externals | client-externals | operations.clientExternals, operations.clients |
| POST /api/client-externals/sync | client-externals | same |
| GET, POST /api/app-config/test | app-config | operations.appConfig |
| GET, POST /api/webhooks/backfill-deliveries | webhooks | operations.webhookDeliveries |
| GET, POST /api/webhooks/backfill-external-actions | webhooks | operations.webhookEvents, operations.externalActions |
The client-externals routes are migration targets rather than ongoing residence: the canonical Person-externals reverse-lookup is the Identity Contract v1 endpoint Platform shipped per 2026-05-09-platform-identity-v1-shipped, and consumers should be re-pointing to that endpoint. The app-config route reads alias maps for Airtable sync secrets and Square tokens, which is Platform's config rail. The webhook backfill routes are eventing-rail observability.
Revenue, propose handoff (22 routes)
The largest chunk. Every route here reads or writes one or more Revenue-owned tables (orders, credits, refunds, invoices, payment-processor refs, ledger), per coordination/domains/revenue.md's "Orders (ord_), credit accounts (cra_), credit reservations (crr_), ledger entries (led_), refunds (ref_), payment-method-on-file, external account references."
| Route | Module | Airtable tables |
|---|---|---|
| POST /api/orders/open | orders | operations.orders, operations.orderItems |
| POST /api/orders/apply-invoice-payment | orders | operations.orders, operations.invoices |
| POST /api/orders/apply-refund | orders | operations.orders, operations.refunds |
| POST /api/orders/resolve-redemptions | orders | operations.orders, operations.promotionRedemptions |
| POST /api/order-externals | orders | operations.orderExternals |
| POST /api/order-externals/charge | orders | operations.orderExternals |
| POST /api/process-order-billing | orders | operations.orders, operations.invoices |
| POST /api/send-invoice | invoices | operations.invoices, operations.invoiceExternals |
| POST /api/reconcile-invoice-externals | invoices | operations.invoiceExternals |
| POST /api/credits/accounts/ensure | credit-accounts | operations.creditAccounts |
| POST /api/credits/ledger/entries | credit-ledger-entries | operations.creditLedgerEntries |
| POST /api/credits/lessons/debit | lesson-debit | operations.creditLedgerEntries, operations.lessons |
| POST /api/credit-ledger-entries/recognize | credit-ledger-entries | operations.creditLedgerEntries, operations.revenueRecognitions |
| POST /api/credit-ledger-entries/contra-recognize | credit-ledger-entries | same |
| POST /api/refunds/process | refunds | operations.refunds, operations.refundExternals |
| POST /api/refund-items/debit | refund-items | operations.refundItems, operations.creditLedgerEntries |
| POST /api/promotion-redemptions/stamp-snapshots | promotion-redemptions | operations.promotionRedemptions, operations.promotions |
| POST /api/sync-card-external | card-externals | operations.cardExternals |
| POST /api/card-externals/sync | card-externals | operations.cardExternals |
| POST /api/provider-accounts | provider-accounts | operations.providerAccounts |
| POST /api/webhooks/square | app/webhooks/square (re-exported) | operations.webhookEvents and downstream Revenue tables |
| POST /api/webhooks/backfill-square | webhooks | operations.webhookEvents (Square subset) |
Delivery, propose handoff (13 routes)
Lessons, Participant (legacy "Client Profile"), and the lock state machine. Per coordination/domains/delivery.md: Participant (par_), lesson scheduling, attendance, coach assignment, the credit reservation lock state machine (ADR-0006).
| Route | Module | Airtable tables |
|---|---|---|
| POST /api/lessons/cancel | lessons | operations.lessons |
| POST /api/lessons/complete | lessons | operations.lessons |
| POST /api/lessons/debit | lessons | operations.lessons, operations.creditLedgerEntries (cross-domain) |
| POST /api/lessons/no-show | lessons | operations.lessons |
| POST /api/lessons/process-outcome | lessons | operations.lessons |
| POST /api/client-profiles | client-profiles | operations.clientProfiles, operations.clientLessonSummaries |
| POST /api/clients/profiles/backfill-lesson-summaries | client-profiles, lesson-summaries | same plus operations.lessons |
| POST /api/clients/profiles/ensure-lesson-summary | same | same |
| POST /api/clients/profiles/recompute-all-summaries | same | same |
| POST /api/clients/profiles/recompute-lesson-summary | same | same |
| POST /api/reservations/create | reservations to credit-reservations | operations.creditReservations |
| POST /api/reservations/lock | same | same |
| POST /api/reservations/void | same | same |
The reservation routes are the most coordination-heavy because the underlying state is jointly owned (lock state in Delivery per ADR-0006, funding sub-state in Revenue). The route surface itself is a state-transition driver, which puts it on the Delivery side, but the move warrants a coordinated Delivery and Revenue ack.
Cross-cutting, needs ADR (3 routes)
The external-actions surface is a generic outbound provider write-buffer with retry classification. It touches multiple domains' tables (externalActions, clients, clientExternals, providerAccounts). Two reasonable shapes are on the table: (a) cross-domain Platform infrastructure (one queue, multiple producers), or (b) per-domain write-buffers (each domain owns its own External Actions surface). This should not relocate without a deliberate decision.
| Route | Module |
|---|---|
| POST /api/external-actions | external-actions |
| POST /api/external-actions/retry | external-actions |
| POST /api/external-actions/sync | external-actions |
Approach
Each move follows the same shape. The receiving domain stands the route up under its own repo. The Growth route stays in place as a thin proxy for one deprecation window (org standard from _OPERATOR.md Contracts section: two weeks). The proxy then deletes. Callers (the web repo's lesson-request POST, the Square webhook handler, the Meta webhook handler, internal cron callers, etc.) see no contract change during the cutover.
Proposed sequencing, smallest and lowest-risk first:
quo-contactsto Sales. Brand-new, no Airtable predecessor, no caller surface to deprecate. Smallest move; serves as the template.app-config/testand the two webhook backfill routes to Platform. Cross-cutting infrastructure; low caller impact.client-externals(both routes) to Platform. Migration target rather than ongoing residence; coordinated with the Identity Contract v1 endpoint that supersedes them.- The Revenue bundle. Sequencing within the bundle is Revenue's call.
- The Delivery bundle. Reservations last because of the joint lock-state / funding-sub-state coordination with Revenue.
- The
external-actionsADR. Drafted before any of the three routes moves.
Growth proceeds as engineering capacity allows, consistent with the no-dates / continuous-deployment mode declared in 2026-05-23-platform-sunset-directive-superseded. The order above is a proposal, not a calendar.
Asks
- Platform, Sales, Delivery, Revenue: ack the bucketing for routes proposed to your domain. Push back on anything that lands wrong. If you have sequencing constraints (Postgres-cutover work in flight that would conflict with absorbing a route), name them in the reply.
- Each receiving domain: when a handoff is ready to start, file a per-route (or per-bundle) handoff memo as a reply on this thread. The receiving-side commitment to absorb the route lives on the reply, not on this memo.
- Platform specifically: indication on the
external-actionsshape question. If Platform plans to steward this as cross-domain infrastructure, the decision lands as an ADR; if Platform prefers per-domain ownership, the routes scatter to Revenue, Delivery, and Platform per the tables they touch.
Soft response window: 2026-06-08 (two weeks). No hard date; the carve-up does not gate any other commitment Growth currently holds.
References
coordination/domains/growth.md,coordination/domains/platform.md,coordination/domains/sales.md,coordination/domains/delivery.md,coordination/domains/revenue.md. Per-domain canonical scope.coordination/_project-instructions/_OPERATOR.md. Domain scope and Contracts sections (two-week deprecation window).2026-05-23-growth-postgres-pilot-scope. The pilot-scope memo that frames what stays in Growth.2026-05-23-platform-sunset-directive-superseded. The no-rocks, no-dates planning mode this memo files under.2026-05-09-sales-q2-airtable-sunset-scoping. Sales' note that Quo has no Airtable predecessor.2026-05-09-platform-identity-v1-shipped. The Person-externals reverse-lookup endpoint that supersedes the Growth-sideclient-externalsroutes.growth/src/config/airtable-schema.ts. The core and operations base split that drives the bucketing.