feat(ramp): headless buy playground and Phase 3 session API#29144
Merged
Conversation
Add a phased plan under app/components/UI/Ramp/headless/ outlining how to expose the Unified Buy v2 flow to external consumers via a useHeadlessBuy hook and a dev-only playground screen, including the session registry pattern, the Headless Host stack-base solution for the Transak auth loop, and the order-callback path replacing the order processing redirect.
Introduces a dev-mode-only playground screen reachable from the Buy/Sell settings (gated by isInternalBuild) to incrementally prototype the useHeadlessBuy hook. The screen currently surfaces useRampsController state in collapsible sections for region, providers, tokens and payment methods, lets the user select a provider/token, attempts to default to mUSD on Linea and the Transak native provider when available, and shows a summary of the active selections.
Introduce a read-only `useHeadlessBuy` hook that wraps `useRampsController` and exposes the catalog (tokens, providers, paymentMethods, countries), `userRegion`, `orders`, `getOrderById`, an aggregated `isLoading` / `errors` surface, and a `getQuotes(params)` helper that resolves the wallet address from the asset's chain id so external callers can fetch quotes without pre-seeding controller state. Wire the playground to the new hook: amount input, country/payment-method pickers, "Get quotes" button, and a quote list that renders the resolved payment method name, fee breakdown, reliability score and tag badges. A clearly delimited "headless consumer simulation" section uses hardcoded asset/payment/provider IDs that can be overridden from the pickers above (with Reset links) so the hook is exercised in isolation from the controller.
Add a module-level session registry that holds non-serializable headless buy callbacks keyed by sessionId, and a startHeadlessBuy API on useHeadlessBuy that creates a session and navigates into the existing BuildQuote screen with the headlessSessionId on params. The screen does not branch on the param yet — Phase 3 only plumbs the id and validates the lifecycle end-to-end through the playground's event log. Includes the Phase 3.1 follow-up: startHeadlessBuy no longer writes to RampsController. The previous pre-seed called setSelectedPaymentMethod and setSelectedProvider with raw ids, but those setters take full PaymentMethod / Provider objects and the catalog can still be loading at that point. Inputs now live on the HeadlessSession only; the destination screen resolves them when the catalog is hydrated. Playground gains a noticeable headless-consumer simulation block with a "Start headless buy" button, a cancel control and an event log so we can exercise the lifecycle (started → onOrderCreated / onError / onClose → ended) without leaving the dev sandbox. PLAN.md is updated with Phase 3.1 (this fix), an expanded Phase 4 description, a new Phase 5b (quote-first headless start path) and an expanded Phase 8 that captures the auto-onClose-on-dismissal work and the closeSession idempotency contract.
Contributor
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - draft PR All E2E tests pre-selected. |
saustrie-consensys
approved these changes
Apr 21, 2026
|
Contributor
|
✅ E2E Fixture Validation — Schema is up to date |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
This draft PR stacks the Headless Buy proof-of-concept work through Phase 3 (plus Phase 3.1) on top of
main. It is intended for incremental review and CI validation before follow-up phases (BuildQuote refactor, Headless Host, routing callbacks).Scope vs
main(full branch)isInternalBuild), route registration, and a scrollable UI to inspectuseRampsControllercatalog data with accordions, selectors, and summary.useHeadlessBuyread-only facade: tokens, providers, payment methods, countries, orders,getQuotes, aggregated loading/errors; playground sandbox simulating an external consumer (hardcoded defaults + accordion overrides, quote details, i18n).sessionRegistry(module-levelMapfor callbacks + params),startHeadlessBuy(creates session, navigates to BuildQuote withheadlessSessionId),BuildQuoteParams.headlessSessionIdplumbing, playground Start headless buy / Cancel / event log, and tests.Diff vs previous POC branches (incremental)
main...poc/headless-buy-phase-1PLAN.mdscaffold.poc/headless-buy-phase-1...poc/headless-buy-phase-2useHeadlessBuy,types, barrel, playground wiring to hook (getQuotes, amount, quotes UI, sandbox, i18n).poc/headless-buy-phase-2...poc/headless-buy-phase-3sessionRegistry+ tests,startHeadlessBuy+ tests, BuildQuote param + nav test, playground session lifecycle UI + tests,PLAN.mdupdates below.Full branch vs
main:main...poc/headless-buy-phase-3.PLAN.mdchanges from Phase 2 → Phase 3useContinueWithQuote(quote, ctx)and reuse by BuildQuote + headless callers; new Phase 5b (quote-firststartHeadlessBuy({ quote })); Phase 8 expanded for flow dismissal →onClose,closeSessionidempotency, anduseHeadlessSessionDismissal(BuildQuote now, Headless Host after 4b).useHeadlessBuy.PaymentMethod/Providerobjects, not ids) and catalog hydration race; resolution is params on session only, resolution at destination.HeadlessBuyParams, Host behavior forcontinue-with-quote, tests, and deliverable for devs who already have aQuotefromgetQuotes.user_dismissed,completed,consumer_cancelled,unknown),useHeadlessSessionDismissal, centralizedcloseSession, tests, and note that today the playground still needs manual cancel until this ships.Not in this PR yet:
BuildQuotedoes not readheadlessSessionIdor callsession.callbacks— that remains Phase 4–8 per the plan. Consumercancel()from Phase 3 is the only guaranteed session teardown besides GC.Changelog
CHANGELOG entry: null
Related issues
Fixes:
Jira: TRAM-3524 | TRAM-3525 | TRAM-3526
Manual testing steps
Screenshots/Recordings
Before
N/A
After
headlessbuy_sandbox.mp4
Pre-merge author checklist
Performance checks (if applicable)
trace()for usage andaddTokenfor an exampleFor performance guidelines and tooling, see the Performance Guide.
Pre-merge reviewer checklist
Note
Medium Risk
Adds new navigation routes, a sizable new dev-only screen, and a new headless buy hook/session registry that touches quote fetching and navigation into the buy flow; mistakes could impact Ramp navigation or quote requests despite UI gating to internal builds.
Overview
Introduces an internal-build-only “Headless Buy playground” reachable from Ramp Settings, plus a new
Routes.RAMP.HEADLESS_PLAYGROUNDstack screen.Adds a new
useHeadlessBuyfacade and supportingheadless/modules, including an in-memorysessionRegistryfor storing per-attempt params + non-serializable callbacks and astartHeadlessBuyAPI that creates a session, navigates intoBuildQuotewith a threadedheadlessSessionId, and supports programmatic cancel viaonClose({ reason: 'consumer_cancelled' }).Plumbs
headlessSessionIdthroughBuildQuoteParams, expands i18n strings for the playground UI, and adds comprehensive unit tests covering the Settings entry gating, playground behavior,getQuoteswallet resolution, session registry TTL/CRUD, and headless session navigation/cancel.Reviewed by Cursor Bugbot for commit 016bd5e. Bugbot is set up for automated code reviews on this repo. Configure here.