Payment Process Overview
Consolidated notes on the foodpanda payment stack across the pd-microfrontend, pd-pablo-payment-gateway, pd-ops-portal-payments, and pd-ops-portal-wallets repositories. Paths cited inline reference the relevant implementation spots.
Repository Roles
pd-microfrontend: customer-facing web microfrontends, including the sharedPaymentReact library and checkout integration (packages/libraries/payment/README.md:1,packages/checkout-microfrontend/services/place-order-service/place-order-service.ts:1).pd-pablo-payment-gateway: Go services (REST + gRPC) orchestrating Alfred, wallet, customer, and vendor dependencies for purchases and direct payments (pkg/service/v1/payment.go:1).pd-ops-portal-payments: Ops Portal plugin used by finops/admin teams to create and edit payment methods and toggles (src/components/payment-method-form/PaymentMethodForm.tsx:45).pd-ops-portal-wallets: Ops tooling for cashback campaigns and wallet disbursements that also consumes payment- and wallet-admin APIs (src/global/api.ts:1).
Web Purchase Flow (Order Checkout)
sequenceDiagram autonumber participant Client as Web Client participant CheckoutMFE as Checkout MFE (`pd-microfrontend`) participant PaymentLib as Payment Library participant Pablo as Pablo REST (`pd-pablo-payment-gateway`) participant Alfred as Alfred participant PSP as PSP Client->>CheckoutMFE: Load /checkout CheckoutMFE->>PaymentLib: Initialise with appConfig & context PaymentLib->>Pablo: POST /api/v5/purchase/intent (create) Pablo->>Alfred: Create purchase intent Alfred-->>Pablo: Intent response Pablo-->>PaymentLib: Intent data (methods, balances) PaymentLib-->>CheckoutMFE: onPaymentsUpdate(payload) Client->>CheckoutMFE: Place Order CheckoutMFE->>Pablo: POST /api/v5/cart/checkout (payload incl. purchase_intent_id) Pablo->>Alfred: Confirm purchase intent Alfred->>PSP: Authorise / redirect PSP-->>Alfred: Redirect details Alfred-->>Pablo: Confirm response (incl. redirect URL) Pablo-->>CheckoutMFE: Checkout result (redirectUrl or success) CheckoutMFE-->>Client: Redirect to PSP/Bruce or success page
Detailed Steps
- Initialisation – Checkout MFE renders the shared
<Payment>component, passingappConfig,context="Purchase", user data, and tokenisation callbacks (packages/libraries/payment/payment.tsx:1). - Create Intent – For purchase context, the Payment library dispatches
createIntent, which shapes aPurchaseIntentRequestand posts viapurchaseIntentProvider(wrapping FD APIPOST /api/v5/purchase/intent) (packages/libraries/payment/services/create-purchase-intent/create-purchase-intent.ts:6,openapi.yaml:3012). - Surface Methods – The returned intent is adapted into local models, default method chosen, and
onPaymentsUpdatefired so the checkout flow knows the selected instrument and validation state (packages/libraries/payment/redux/thunks/create-intent/create-intent.ts:79). - Adjust Intent – If totals or method change,
updateIntentPUTs the new selection back to Pablo/Alfred, embeddingselectedPaymentInstrumentIdwhen available (packages/libraries/payment/redux/thunks/update-intent/update-intent.ts:67,packages/libraries/payment/services/update-purchase-intent/update-purchase-intent.ts:7). - Submit Order – On confirm, the checkout service builds
orderPayloadcontainingpayment.methods(from the library), thepurchase_intent_id, and a redirect template URL before callingplaceOrderProvider(FDPOST /api/v5/cart/checkout) (packages/checkout-microfrontend/services/place-order-service/place-order-service.ts:72). - Status Polling – While waiting for PSP callbacks, the UI polls Pablo’s
GET /api/v5/payment/statusviahandlePaymentStatus, handlingsuccess,pending(with retry), andaction_required(redirect) (packages/checkout-microfrontend/services/order-payment-service/handle-payment-status.ts:61,openapi.yaml:3408). - Redirect Handling – PSP/Bruce redirects land on
/payments/handle-payment, which sets cookies for checkout errors or forwards to order tracking on success (packages/payments-microfrontend/payments/handle-payment/router.tsx:8).
Key API Touchpoints
| Step | Endpoint | Repo Entry | Notes |
|---|---|---|---|
| Create intent | POST /api/v5/purchase/intent | openapi.yaml:3012 | Query params include, optional fast-top-up. |
| Update intent | PUT /api/v5/purchase/intent/{intentId} | packages/libraries/payment/services/update-purchase-intent/update-purchase-intent.ts:7 | Adds paymentSessionDetails with selected instrument. |
| Checkout | POST /api/v5/cart/checkout | packages/checkout-microfrontend/services/place-order-service/place-order-service.ts:72 | Includes external_payment_url_template for fallback tracking. |
| Status poll | GET /api/v5/payment/status | packages/checkout-microfrontend/providers/place-order-provider/payment-status-provider.ts:5 | Requires purchaseId, platformReferenceId, attempt. |
Direct Payment Contexts
Direct payments cover wallet top-ups, subscriptions, dine-in, PandaGo, donations, etc. (docs/payment-and-purchase.md:5).
sequenceDiagram autonumber participant Client as Channel (Web/App) participant Pablo as Pablo REST/gRPC participant Alfred as Alfred Client->>Pablo: POST /api/v5/payment/intent (optional) Pablo->>Alfred: Create Direct/Donation intent (per context) Alfred-->>Pablo: Intent details (session) Pablo-->>Client: Response (paymentSessionId, methods) Client->>Pablo gRPC: CustomerPay / MerchantPay Pablo->>Alfred: Confirm payment (TransactionInitiator CIT/MIT) Alfred-->>Pablo: Confirm result Pablo-->>Client: PayResponse (status, redirect) Alfred-->>Pablo: Callback updates (state changes)
Context Strategies
- CustomerPay (CIT) – The gRPC service validates the payment strategy, fetches wallet auth, stores a
payment.Entity, and confirms via Alfred, tagging the transaction initiator as customer (pkg/service/v1/payment_customerpay.go:43). - MerchantPay (MIT) – Used for subscription renewals with whitelisted payment methods; Pablo creates and confirms direct payments without an initial intent call (
docs/payment-and-purchase.md:83). - Donation / Dine-in / PandaGo – Strategy factory decides whether to call Alfred purchase intents or dedicated APIs (
docs/payment-and-purchase.md:20).
Direct Payment Intent Payload
POST /api/v5/payment/intent expects payment details (amount, filterPaymentMethods) plus paymentContext discriminator to resolve the correct backend strategy (openapi.yaml:3346).
Payment Library Internals
- Props Contract –
<Payment>requiresappConfigwith FD API credentials,context, hosted credit-card props, tokenisation callbacks, transaction amount, andonPaymentsUpdate. Optional props includeintentData(for non-purchase contexts) andpurchaseIntentRequestBody(purchase context) (packages/libraries/payment/README.md:7). - Tokenisation Flow – The library coordinates host-bruce tokenisation via
proceedPaymentStatus,onTokenizationStart,onTokenizationComplete, andonTokenizationFailure, ensuring encrypted payloads are present before confirming payment (packages/libraries/payment/README.md:53). - State Management – Redux thunks encapsulate intent creation/update, storing payment details, balance state, default selection, and validation status. They also generate success and error messaging for the UI (
packages/libraries/payment/redux/thunks/create-intent/create-intent.ts:43,packages/libraries/payment/redux/thunks/update-intent/update-intent.ts:67). - Providers –
purchaseIntentProviderappends locale/cashback query params, retrieves the auth cookie, and addsX-PD-Language-IDso Alfred returns localised content (packages/libraries/payment/providers/purchase-intent-provider/purchase-intent-provider.ts:14).
Payment Status & Callbacks
stateDiagram-v2 state "Created" as Created state "Confirmed" as Confirmed state "Committed" as Committed state "Captured" as Captured Created --> Confirmed Confirmed --> Committed Committed --> Captured
- Pablo records payment state transitions and publishes SNS events after confirmations so Cart and other services can react (
docs/payment-and-purchase.md:188). - Alfred invokes Pablo callbacks at
/api/v5/alfred/callbackfor payment status updates, cashback, SAP invoicing, and notifications (docs/payment-and-purchase.md:238). - Instruction callbacks differentiate purchase vs payment owners, retry failed confirmations, notify Redis/CCS, and trigger invoices (
docs/payment-and-purchase.md:288).
Operational Tooling
- Payment Method Admin – Ops users with
admin/editorroles can create or edit payment methods via the React form, which maps UI fields (hosted, tokenisation, surcharges, is_pablo_processable) into Pablo’s admin schema (src/components/payment-method-form/PaymentMethodForm.tsx:45,src/helpers/generate-payment-method-api-model/generate-payment-method-api-model.ts:6,src/global/api.ts:3). - Wallet Ops Portal – Provides campaign, banner, and cashback disbursement management against
/api/v5/wallet/admin/*, and also reads configuration/payment method lists for wallet features (pd-ops-portal-wallets/src/global/api.ts:1).
Observations & Gaps
- The Cart service invoking
PaymentService/Pay(Pablo gRPC) is external; request bodies and error handling between Cart and Pablo are inferred from documentation, not available in these repos. - PSP/Bruce frontends handling redirects, hosted forms, and 3DS challenges are out of scope here; only redirect URLs and cookies are visible.
- Feature flag lookups (“FwF”) and country/vendor payment availability checks happen server-side in Pablo but implementation details reside in other packages not included above.
- Native/mobile clients for direct payments (subscriptions, dine-in, donations) follow similar patterns but their codebases are not part of this workspace, so platform-specific nuances remain unknown.