Primary path prefixes
Normal checkout runs under /secure-checkout. Seamless migration mirrors the route tree
under /customer-transfer/secure-checkout.
Engineering docs
web-shop-checkout is Vodafone's route-driven checkout and order-completion app for
online shopping journeys outside VOXI. The repo combines a React + MobX client, a shared route/config
layer, and Express/Vite server runtimes that proxy backend APIs, auth, flags, and AIM mocks.
Normal checkout runs under /secure-checkout. Seamless migration mirrors the route tree
under /customer-transfer/secure-checkout.
Browser load goes through index.tsx, app.tsx, routes.tsx,
Wrapper, then either the panel-driven checkout shell or a standalone route.
JourneyStore, PanelsStore, CheckoutStore,
FeatureFlagStore, and ContentStore jointly determine which panels, copy,
routes, and modals exist at runtime.
The repo owns the main accordion checkout, the order-processing poller, accepted/conditional/declined outcome pages, 3DS validation, device-loan routes, and an assisted-channel summary route.
src/client/routes.tsx,
AppInit,
the MobX stores under src/client/app/stores, and
the server runtimes under src/server.
The app is a React 18 checkout running on a MobX singleton-store model, fronted by React Router and backed by Express/Vite middleware, Contentful, LaunchDarkly, Adobe Target, and AIM.
The local developer path in the README is: install dependencies, copy env templates, generate the local
certificate, run the HTTPS server, add ?debug, and then set or generate a basketId.
yarn install.yarn certgen once to generate the localhost certificate.yarn start.https://localhost:8000/secure-checkout?debug.basketId..env files are intentionally not committed. Use the provided .example
files as templates.
yarn start:prod.
There are three runtime layers to keep in mind: client boot and route ownership, MobX-driven journey/panel orchestration, and the server middleware stack that injects auth, flags, proxies, and mocks.
index.tsx starts the session, then
CheckoutApp creates the router, while
Wrapper injects theme, i18n, suspense, and the
lazy debug panel.
AppInit
initialises flags, checkout/content/basket readiness, then journey detection, JSON schemas, panel
instances, and analytics before route UIs render as ready.
PanelsStore chooses a
journey-specific interface list from
journeyInterfaces.ts,
creates one PanelStore per step, and drives hidden/summary/active transitions with MobX reactions.
The main accordion checkout is only one surface. Order processing, order completion, 3DS, loan review/signing, and assisted-channel summary are separate route owners with their own runtime loops.
The graph below follows the real runtime hand-off from browser boot into the route tree, AppInit, checkout/panel orchestration, order submission, processing, and final outcome pages.
systemCfg.pathPrefix, which is currently
/secure-checkout. Seamless migration mirrors part of the tree under
/customer-transfer/secure-checkout.
This is the runtime ownership map from route shells down into meaningful children. The groups are ordered from shared owners to deep panel families and standalone routes.
The app uses MobX singleton stores rather than React context for shared state. The strictest rules live in
CheckoutStore, which calls configure({ enforceActions: "always" }), while
other stores derive branch conditions or expose domain-specific data slices.
CheckoutStore holds checkout data, basket IDs, order flags, redirect state, and many
computed values panels read directly.
JourneyStore derives logged-in, bingo, PAYG+, broadband, migration, business, and
network-trial modes from checkout data and flags.
PanelsStore turns the journey model into visible panel instances, active-step order, and
summary/hidden/error transitions.
A successful checkout submission is not a single request. The normal path is checkout bootstrap, basket hydration, panel-specific PUT/POST submissions, optional payment/3DS hand-off, order-state polling, and then a refreshed order-complete render.
The repo ships two server entrypoints that share most of the same middleware chain: a production Express runtime and a Vite dev server. Both are responsible for route prefixing, auth/session middleware, flags, proxying, and AIM support.
Content and toggles arrive through multiple channels. Contentful-backed content comes through
ContentService and is consumed by both newer stores and a few tactical legacy calls. Feature
flags arrive server-side through LaunchDarkly and client-side through Adobe Target on
window.vfukTnt.
ContentStore.initStore() gates notification/order-complete fetches behind flags.PanelsStore.setPanelCopy() still owns panel-copy fetching and parsing.CheckoutStore.initStore() still contains tactical Contentful fetch calls for
notifications, order-complete content, and state notifications.
JourneyStore.contentfulJourneyType.
?debug matters in local development.
?debug.The inventory below is broad on purpose: it covers route owners, panel orchestration, key panels, stores, and service/runtime modules that materially affect behavior.
The repo is split between src/client, src/server, shared route config, worker
transforms, Cypress/Jest harnesses, and AIM mock payloads. Path aliases in tsconfig.json are
used heavily across the codebase.
Most local workflows are script-driven through package.json, with Jest for unit coverage,
Cypress for E2E and visual runs, and Sonar/ESLint/TypeScript for quality gates.
A few parts of the runtime are intentionally external or only partially visible from this repository. They are worth calling out so new engineers know where code evidence ends.
The checkout does not render its own order-summary UI. Instead it delegates that work to an independently
deployed micro-frontend — the federated basket — loaded at runtime via the Vodafone
Federated Module system (@vf/federated-react, @vf/federated-core). This section
explains exactly what "federated" means here, how the basket data flows in, and which parts of the
checkout it affects.
Vodafone's online properties use a micro-frontend architecture where different squads own
different UI surfaces. The basket is maintained by a separate team and deployed independently as a remote
bundle. When web-shop-checkout needs to show an order summary (in ReviewYourOrder
and on the FakeFederatedBasket dev route), it pulls that remote bundle from a known URL
(/basket/federated) and mounts it inside the page. The checkout never contains the basket
rendering code; it only acts as a host.
The federated module is fetched from /basket/federated. In local dev this URL is
proxied so the basket team's own dev server (or a mock) can respond. In production the path resolves
to the basket squad's deployed CDN asset.
@vf/federated-react wraps the remote bundle in a React component.
ReviewYourOrder renders that component — named vfuk-BasketContainer — inside
its JSX tree. If the remote bundle has not yet loaded, a loading skeleton is shown instead.
The federated bundle executes in its own JS scope. It brings its own React version, its own CSS, and its own state. The checkout cannot directly call functions inside it or read its internal store. The only contract is the props interface and the event bus.
A /fake-federated-basket route (registered only when systemCfg.isDev is
true) mounts a local placeholder so developers can work on the review panel without needing the real
basket bundle running.
The basket needs to know what is in the order so it can display a correct summary. The checkout owns that
data — it is fetched from the backend and stored in CheckoutStore.basketData. Two
mechanisms send that data to the federated component:
When ReviewYourOrder mounts vfuk-BasketContainer it passes
checkoutStore.basketData as a prop (typically called basketData or
equivalent). This gives the federated component its initial snapshot of the order — products,
prices, discounts, delivery charges, and totals — without any further network call.
The checkout emits a basket:data event through eventService.emit()
whenever CheckoutStore.updateBasketData() is called — for example after a panel
submission changes delivery options or a promo is applied. The federated basket listens for this
event and re-renders its summary accordingly. This keeps the displayed totals in sync without a
full page reload.
basketData is the raw basket payload fetched from
GET /api/basket/v2/basket/{basketId} and reshaped by the basket web worker. It is the same
data that BasketStore uses to build payment-panel breakdowns and order-complete summaries.
Key sections include:
The primary host. The federated basket renders the full order summary card inside this panel. The checkout wraps it in its own panel chrome (header, errors, T&C checkbox, submit button) but the product listing is entirely basket-team code.
Consumes the same raw basket payload via the web worker to produce the breakdownSections
and totals that the UpfrontPayment panel and order-complete screens consume. The basket
store and the federated component read the same source of truth but render different views of it.
Called after every panel submission that could affect basket content (delivery changes, address
changes, promotions). It re-fetches from the basket API and re-emits the basket:data
event so the federated basket re-renders automatically.
A local stub route at /fake-federated-basket that mounts a simplified basket mock.
Used during development when the real basket bundle is unavailable or when testing checkout layout
without a live basket deployment.
basketData that CheckoutStore holds, the updateBasketData()
call chain after a panel submit, or the federated basket bundle itself (which is a separate
deployment and may need its own investigation with the basket team).
The first panel in almost every journey. It collects the customer's identity — personal details,
customer type, and journey-specific fields — and is the earliest branch point in the checkout.
The optimised variant (OptimisedAboutYou) is an Adobe Target experiment with the same
backend contract.
src/client/app/components/panels/AboutYou/AboutYou.tsx
Optimised variant: OptimisedAboutYou/OptimisedAboutYou.tsx
aboutYouStore (or optimisedAboutYouStore for the CRO variant).
Both delegate submission to panelStore.submit().
Always the first visible panel. Shown for every journey type. Cannot be skipped unless the customer is already fully authenticated and the journey interface excludes it.
| Method | Path | Purpose |
|---|---|---|
PUT | /api/checkoutInfo/v2/{checkoutId}/personalDetails | Saves personal details and customer type to the backend checkout session. |
| Field | Type | Condition | Source |
|---|---|---|---|
customerType | string | Always | Radio button selection: Consumer, SoleTrader, LimitedCompany, Partnership |
title | string | Always | Dropdown (Mr, Mrs, Ms, Dr, …) |
firstName | string | Always | Text input |
lastName | string | Always | Text input |
email | string | Always | Text input — validated for uniqueness before submit via checkUsernameEmailUniqueness() |
phoneNumber | string | Always | Text input |
dateOfBirth | string (ISO) | Consumer only | Date picker (day / month / year dropdowns) |
nationality | string | Consumer only | Dropdown selection |
employmentStatus | string | Consumer, credit journeys | Dropdown (Employed, Self-Employed, Retired, …) |
companyName | string | Business customer types | Text input |
currentNetworkProvider | string | Network Trial HBB journeys only | Dropdown |
GET /checkoutInfo/v2/{checkoutId}/personalDetails/schema during app init.statusInfo.status that is not an error for the panel to transition to summary state.POST /authorization/v2/action/doesUsernameExist — a non-unique email blocks submission before the panel PUT is even attempted.optimisedAboutYouPanel) and is only available
for Limited Company / Partnership customer types in specific journey interface sets.
A confirmation-style panel — not an input form. The customer reads an affordability summary table and checks a box to confirm their circumstances have not changed since they first applied. It is used in Bingo (device finance) journeys where a credit decision already exists but a formal affordability affirmation is required before the loan documents can be shown.
src/client/app/components/panels/Affordability/Affordability.tsx
yourFinancesStore — the same store that drives YourFinances. The
affordability table it renders reads loanAgreementStore for loan copy.
Shown for Bingo / device-finance journeys when the journey interface list includes it.
Hidden for income-check journeys (which use YourFinances instead).
| Method | Path | Purpose |
|---|---|---|
PUT | /api/checkoutInfo/v2/{checkoutId}/affordabilityDetails | Submits the customer's affordability confirmation to the backend. |
| Field | Type | Value | Source |
|---|---|---|---|
noChangeInCircumstances | boolean | true | Checkbox — must be ticked by the user. The field is only submitted when true; leaving it unchecked blocks the continue button. |
noChangeInCircumstances: true.affordabilityDetails object in the checkout response.Collects up to three years of UK address history. The front-end uses a premises lookup service to let customers find their address by postcode, then records how long they lived at each address and their residential status. A sibling panel — AddressCheck — handles a simpler variation for authenticated users who need to confirm (rather than enter) their address.
AddressDetails/AddressDetails.tsx — full address history entry.
AddressCheck/AddressCheck.tsx — confirm existing account address.
addressesStore — manages multiple address entries, date-moved-in validation,
and the premises lookup interaction. AddressCheck reads from the same store.
Required for anonymous and credit-check journeys. AddressCheck replaces it for
authenticated users on PAYM or home-moves journeys. Both panels are absent from
journey interfaces that do not require a billing address history (e.g., some PAYG+ flows).
| Method | Path | Purpose |
|---|---|---|
GET | /api/premise/address?postcode={}&houseNumber={} | Address lookup via premiseService — called when the customer types a postcode. Returns a list of matching premises to pick from. |
PUT | /api/checkoutInfo/v2/{checkoutId}/personalDetails | Saves the full address history (residential addresses, dates, residential status) to the checkout session. |
| Field | Type | Condition | Source |
|---|---|---|---|
addresses[].flatNumber | string | If applicable | Pre-filled from premises lookup or typed manually |
addresses[].buildingNumber | string | Always (primary address) | Premises lookup result |
addresses[].buildingName | string | If applicable | Premises lookup result |
addresses[].street | string | Always | Premises lookup result |
addresses[].city | string | Always | Premises lookup result |
addresses[].postcode | string | Always | Customer-entered postcode used for the lookup |
addresses[].country | string | Always | Defaulted to GB or selected from dropdown for non-UK addresses |
addresses[].dateMovedIn | string (YYYY-MM) | Always | Month/year picker in the panel |
addresses[].residentialStatus | string | Always for primary address | Dropdown: Owner, Tenant, Living With Parents, … |
addresses[].currentAddress | boolean | Always | Set to true for the first entry |
dateMovedIn, postcode,
street, and city.residentialStatus.dateMovedIn for each address entry.
The same personalDetails PUT is used.
Lets the customer choose how and where their order is delivered. There are three panel variants
covering different product types: standard Delivery for handsets and SIMs,
BroadbandDelivery for router/equipment shipping, and RedDelivery
for PAYG+ orders that need a combined delivery and billing address step. All three write to the same
backend key (deliveryOptions) via the same PUT endpoint.
Delivery/Delivery.tsx — standard handset / SIM delivery.
BroadbandDelivery/BroadbandDelivery.tsx — broadband router shipping.
RedDelivery/RedDelivery.tsx — PAYG+ combined delivery + billing address.
deliveryStore, addressDeliveryStore (home delivery selection),
broadbandDeliveryStore, redDeliveryStore.
Shown when the basket contains a physical product (handset, router, SIM). eSIM-only or activation-only journeys may skip this panel entirely or show a reduced broadband-activation variant that does not involve an address.
| Method | Path | Purpose |
|---|---|---|
PUT | /api/checkoutInfo/v2/{checkoutId}/deliveryOptions | Initial call to fetch available delivery methods for a given postcode (and later to save the customer's choice). The same endpoint is used for both "get methods" and "save selection". |
GET | /api/premise/address?postcode={} | Address lookup used by RedDelivery and BroadbandDelivery when the customer searches for a delivery address different from their billing address. |
| Field | Type | Value / source |
|---|---|---|
deliveryName | string | Hardcoded 'DeliverToAny' for home delivery. 'ClickAndCollect' for store pick-up. |
deliveryAddress.flatNumber | string | From selected premises result or previously entered address |
deliveryAddress.buildingNumber | string | From premises lookup |
deliveryAddress.buildingName | string | From premises lookup (if applicable) |
deliveryAddress.street | string | From premises lookup |
deliveryAddress.city | string | From premises lookup |
deliveryAddress.postcode | string | Customer-entered search postcode |
deliveryAddress.country | string | Defaulted 'GB' |
deliverySlotId | string | Selected time-slot ID from the list of available slots returned by the first PUT call (if slot selection is available) |
| Field | Type | Source |
|---|---|---|
billingAddress.* | object | Either re-used from billing address (checkbox ticked) or separately searched via premises lookup |
useBillingAddressForDelivery | boolean | Checkbox in the RedDelivery panel UI |
Collects the customer's Direct Debit bank account details so that recurring monthly charges can
be set up. It is a thin shell around ActivePanel (bank details form) and
Summary (the completed state). Editing this panel can also re-open the
Spend Manager panel when bill-capping state is linked.
src/client/app/components/panels/MonthlyPayment/MonthlyPayment.tsx
monthlyPaymentStore. The panel's active/summary toggle is also driven by
checkoutStore.showMonthlyPaymentActive.
Shown when the basket contains a product with a monthly recurring charge (PAYM, SIMO migration, broadband bundles). Not shown for PAYG+ or upfront-only journeys.
| Method | Path | Purpose |
|---|---|---|
PUT | /api/checkoutInfo/v2/{checkoutId}/bankPayment | Saves the bank account details for Direct Debit setup. |
| Field | Type | Source |
|---|---|---|
accountType | string | Dropdown: Personal or Business |
accountHolderName | string | Text input |
sortCode | string | Text input (6 digits, formatted as XX-XX-XX) |
accountNumber | string | Text input (8 digits) |
paymentDay | number | Dropdown: preferred payment day of the month |
The upfront / card-payment panel. It handles one-off charges such as a handset upfront cost, a PAYG+ SIM purchase, or a Bingo device deposit. Because this panel touches raw payment-card data it uses a remote payment iframe for PCI compliance — no card numbers are ever handled by the checkout JavaScript directly.
src/client/app/components/panels/PaymentPanel/UpfrontPayment.tsx
upfrontPaymentStore. Payment options (saved cards) are read from
checkoutStore.checkoutData.paymentDetails.
Shown when the basket includes an upfront payment amount greater than zero. Hidden for
zero-upfront journeys (e.g., SIM-only with no activation fee). PAYG+ uses a slightly
different sub-layout (HybridSection) within the same component.
| Method | Path | Purpose |
|---|---|---|
PUT | /api/checkoutInfo/v2/{checkoutId}/payment/{activeId} | Updates the selected payment card / method choice. |
PUT | /api/checkoutInfo/v2/{checkoutId}/payment/{paymentId}/initiateCardPayment | Initiates a card payment session — called when the customer selects a card type that requires the iframe. Returns the iframe URL and a payment session token. |
| Field | Type | Source |
|---|---|---|
selectedPaymentId | string | Radio button — ID of the card selected from the list of stored cards surfaced by checkout data |
saveCard | boolean | Checkbox — whether to save the card for future purchases (only shown for new cards) |
initiateCardPayment is
called. The response contains an iframe URL.<iframe> — the remote page (owned by the
payment provider) collects the card number, expiry, and CVV.window.makeGetWebPayment() callback on success, which the
checkout intercepts to trigger order submission or 3DS redirect./secure-checkout/card-authentication and must complete the bank challenge before order submission continues.paymentDetails.statusInfo will surface an inline panel error and block progression.An optional panel that appears after Monthly Payment for logged-in customers. It lets them set a bill cap per package to protect against unexpected overage charges. Customers can configure caps immediately or defer to later — both choices are valid completions.
src/client/app/components/panels/SpendManager/SpendManager.tsx
spendManagerStore. Also reads journeyStore to determine whether
the panel should be visible at all.
Only shown for logged-in customers on monthly-payment journeys where spend management features are enabled. Anonymous or PAYG+ journeys do not see this panel.
| Method | Path | Purpose |
|---|---|---|
PUT | /api/checkoutInfo/v2/{checkoutId}/billCapping | Saves the customer's bill-cap selections (or their choice to defer) to the checkout session. |
| Field | Type | Source |
|---|---|---|
billCaps[].packageId | string | Package identifier from checkout data |
billCaps[].capAmount | number | null | Dropdown per package: Off / £5 / £10 / £25 / £50. null means "off". |
deferredSetup | boolean | true when the customer clicks "No, maybe later" — bypasses the selector and submits with no caps set. |
BillCapSelector row per active package; all rows
must have a selection before the continue button enables.Shown for anonymous customers who do not yet have a My Vodafone account. It combines account credentials (email, password, PIN), accessibility preferences, marketing consent, and optional confirmation-letter preferences into a single step. The Preferences panel is a lighter variant for authenticated customers who already have an account but still need to set accessibility and consent preferences.
CreateYourAccount/CreateYourAccount.tsx — anonymous account creation.
Preferences/Preferences.tsx — authenticated preference update.
accountPanelStore, accountSetupStore, pinSetupStore,
accessibilityStore. Preferences uses preferenceStore +
accessibilityStore.
Anonymous journeys only (PAYG+, broadband, standard anonymous PAYM checkout). Logged-in
customers see the lighter Preferences panel instead, or skip account setup
entirely for upgrade journeys.
| Method | Path | Purpose |
|---|---|---|
POST | /authorization/v2/action/doesUsernameExist | Pre-submit uniqueness check on the email / username before the panel PUT is attempted. |
POST | /api/checkoutInfo/v2/checkUsernameEmailExist | Secondary availability check (used in some journeys as an additional validation layer). |
PUT | /api/checkoutInfo/v2/{checkoutId}/personalDetails | Saves email/username and account credentials to the checkout session. |
PUT | /api/checkoutInfo/v2/{checkoutId}/accessibilityDetails | Saves accessibility needs and marketing/personalisation consent flags. |
| Field | Type | Source |
|---|---|---|
email | string | Text input — checked for uniqueness first |
password | string (hashed) | Password field — hashed client-side before any network call; the raw password is never sent |
pin | string | 4-digit PIN input |
confirmationLetterPreference | string | Radio: email / post (shown on some journey variants) |
| Field | Type | Source |
|---|---|---|
accessibilityNeeds | string[] | Multi-select checkboxes: hearing, visual, mobility, etc. |
marketingConsent.email | boolean | Checkbox |
marketingConsent.sms | boolean | Checkbox |
personalisationConsent | boolean | Checkbox |
doesUsernameExist endpoint before the main submit).personalDetails and accessibilityDetails PUTs must succeed before the panel transitions to summary.
The final panel before order submission. It hosts the federated basket component
(the order summary), surfaces any pending panel errors, and exposes the Terms & Conditions
checkbox and the "Place order" button. Clicking "Place order" hands control to
OrderSubmissionRedirectService, which navigates to either the processing screen or
(if 3DS is required) the card-authentication screen.
src/client/app/components/panels/ReviewYourOrder/ReviewYourOrder.tsx
reviewYourOrderStore, checkoutStore.basketData,
panelsStore.isReadyForSubmission, federated basket module
(vfuk-BasketContainer).
Always the last panel in every journey. Becomes active only after all preceding panels have
reached their summary state (panelsStore.isReadyForSubmission === true).
| Method | Path | Purpose |
|---|---|---|
PUT | /api/checkoutInfo/v2/{checkoutId}/personalDetails | Final validation pass — ensures personalDetails.validated is true and defaults any missing fields (e.g., customerType defaults to 'Consumer') before order submission. |
POST | /api/checkoutInfo/v2/{checkoutId}/submit (via OrderSubmissionService) | The actual order submission call — triggers the backend to process the full checkout and begin fulfilment. After this call the user is redirected to /secure-checkout/processing. |
panelsStore.isReadyForSubmission must be true — every panel ahead of
Review Your Order must be in its summary (completed) state./secure-checkout/processing./secure-checkout/card-authentication, the customer completes the bank challenge, then the window.makeGetWebPayment() callback re-enters the submission flow.OrderProcessingService.beginProcessing() polls GET /api/checkoutInfo/v2/{checkoutId}/orderState on the processing screen until a terminal state (accepted / conditional / declined) is reached, then routes to the appropriate /secure-checkout/submitted|conditional|error page.
Every HTTP request this service makes to backend systems, organised by domain. The base path for
all checkout endpoints is /api/checkoutInfo/v2/{checkoutId}. The
{checkoutId} is created on first load and stored in session storage; all subsequent
panel submits reference it. All requests go through DataService.request(), which
adds AIM tracking keys in development mode.
| Method | Path | Caller | Description |
|---|---|---|---|
POST |
/api/checkoutInfo/v2/ |
CheckoutApiService.createCheckout(basketId) |
Creates a new checkout session. Sends basketId (read from cookie). Returns a CheckoutData object containing the checkoutId used by all subsequent calls. |
GET |
/api/checkoutInfo/v2/{checkoutId}/ |
CheckoutApiService.getCurrentCheckoutState() |
Re-fetches the full checkout state. Called on page reload or after a redirect to resume an in-progress checkout. |
GET |
/api/checkoutInfo/v2/{checkoutId}/{schemaName}/schema |
CheckoutApiService.fetchSchema() → ValidationService |
Fetches the JSON Schema for a named panel (e.g., personalDetails, affordabilityDetails). Called during AppInit for all panels in the current journey. |
POST |
/api/checkoutInfo/v2/{checkoutId}/submit |
OrderSubmissionService.submitOrder() |
Submits the completed checkout for fulfilment. Called by ReviewYourOrder when the customer clicks "Place order". Triggers the backend to begin order processing. |
GET |
/api/checkoutInfo/v2/{checkoutId}/orderState |
OrderProcessingService.beginProcessing() |
Polled repeatedly on the processing screen until a terminal order state is reached (accepted / conditional / declined). |
| Method | Path | Panel | Description |
|---|---|---|---|
PUT |
/api/checkoutInfo/v2/{checkoutId}/personalDetails |
About You, Address Details, AddressCheck, BillingAddress, RedDelivery, Create Your Account, Review Your Order (final pass) | The most widely-used panel endpoint. Multiple panels submit to this path but send different field subsets — the backend merges them into the single personalDetails object. |
PUT |
/api/checkoutInfo/v2/{checkoutId}/affordabilityDetails |
Affordability, Your Finances | Saves income/expenditure or the no-change-in-circumstances confirmation. Both panels write to the same key with different payloads depending on journey type. |
PUT |
/api/checkoutInfo/v2/{checkoutId}/deliveryOptions |
Delivery, BroadbandDelivery, RedDelivery | Fetches available delivery methods (first call by getDeliveryMethods()) and then saves the customer's delivery selection and address. |
PUT |
/api/checkoutInfo/v2/{checkoutId}/bankPayment |
Monthly Payment | Saves Direct Debit bank account details (sort code, account number, account holder name, payment day). |
PUT |
/api/checkoutInfo/v2/{checkoutId}/billCapping |
Spend Manager | Saves bill-cap selections per package or records that the customer chose to defer setup. |
PUT |
/api/checkoutInfo/v2/{checkoutId}/payment/{activeId} |
Payment (UpfrontPayment) | Updates the selected payment card / method for the upfront charge. |
PUT |
/api/checkoutInfo/v2/{checkoutId}/payment/{paymentId}/initiateCardPayment |
Payment (UpfrontPayment) | Initiates a card payment session and returns the iframe URL. Called when the customer selects a card option that requires an iframe entry or 3DS challenge. |
PUT |
/api/checkoutInfo/v2/{checkoutId}/accessibilityDetails |
Create Your Account, Preferences | Saves accessibility needs and marketing / personalisation consent flags. |
| Method | Path | Caller / panel | Description |
|---|---|---|---|
GET |
/api/premise/address?postcode={}&houseNumber={} |
premiseService — Address Details, Billing Address, Your Company, Red Delivery |
Address lookup by postcode (and optional house number). Returns a list of matching addresses from Royal Mail PAF. Used anywhere the customer must enter a UK address. |
GET |
/api/utility/company?registrationNumber={}&legalStatus=LC |
CheckoutApiService.getCompanyList() — Your Company (Limited Company) |
Looks up a company by Companies House registration number for Limited Company customers. |
GET |
/api/utility/company?companyName={}&legalStatus=P&postalCode={} |
CheckoutApiService.getCompanyList() — Your Company (Partnership) |
Looks up a company by name and postcode for Partnership customers. |
POST |
/authorization/v2/action/doesUsernameExist |
CheckoutApiService.checkUsernameEmailUniqueness() — About You, Create Your Account |
Checks whether an email address is already registered as a Vodafone username. Called before the personal details PUT to prevent duplicate account creation. |
POST |
/api/checkoutInfo/v2/checkUsernameEmailExist |
CheckoutApiService.checkUsernameEmailAvailability() — Create Your Account |
Secondary availability check used in some journey variants as an additional validation layer before account creation. |
| Method | Path | Caller | Description |
|---|---|---|---|
GET |
/api/basket/v2/basket/{basketId} |
CheckoutStore.updateBasketData() |
Fetches the current basket contents. Called on init and after any panel submission that may change basket totals (delivery change, address change). Result is passed through the basket web worker and stored in checkoutStore.basketData. |
GET |
/api/content/v2/checkout/{journeyType} (Contentful-backed) |
ContentService → ContentStore, PanelsStore |
Fetches Contentful-backed copy for notifications, panel headers, and order-complete content. The journeyType key is derived from JourneyStore.contentfulJourneyType. |
GET = read-only fetch ·
POST = create / action ·
PUT = update panel state.
All requests are proxied through the Express/Vite server middleware stack and include AIM tracking
keys in development mode.