Skip to main content

Payment architecture

The checkout service orchestrates payment processing by coordinating between payment provider services (Stripe, Adyen, PayNL, etc.) and commercetools. Each payment provider is a standalone service that handles communication with its PSP. The provider only updates the Payment object and its transactions. Order-level actions (confirming an order, handling cancellations) are handled by the checkout service through event subscriptions.

Sequence diagram

Creating a payment

When a payment is needed, the frontend calls the createPayment mutation. The checkout service then:

  1. Fetches the order from commercetools
  2. Creates a Payment object on the order with the selected method and payment interface
  3. Delegates to the appropriate PSP service to start a transaction
  4. Returns a redirect URL so the customer can complete payment

The Payment object stores the selected method in paymentMethodInfo.method and the provider identifier in paymentMethodInfo.paymentInterface.

Payment states

The checkout service manages payment state transitions through commercetools state machines. Payment providers transition the Payment to one of these states:

StateKeyEnvironment variable override
InitialPaymentInitialPAYMENT_STATE_KEY_INITIAL
PendingPaymentPendingPAYMENT_STATE_KEY_PENDING
SuccessPaymentSuccessPAYMENT_STATE_KEY_SUCCESS
CancelledPaymentCancelledPAYMENT_STATE_KEY_CANCELLED
FailurePaymentFailurePAYMENT_STATE_KEY_FAILURE

These state objects are defined in the checkout service's Terraform configuration and looked up by key at runtime. You can override the default keys through environment variables if your project uses different naming.

Event-driven order updates

When a payment state changes, commercetools emits a PaymentStatusStateTransition message. The checkout service subscribes to these messages and updates the order accordingly. For example, when all payments on an order reach PaymentSuccess, the checkout service transitions the order's payment state to paid.

This event-driven approach means the checkout service reacts to payment outcomes asynchronously rather than polling for status changes. See Messaging & events for how event subscriptions work across all services.

REST endpoints

A payment provider exposes the following API endpoints:

POST /payment-methods: return the payment methods available for the given cart. The cart ID and other context are passed in the request body.

POST /create: create a payment transaction. This starts the payment flow and returns a redirect URL for the customer to complete payment at the PSP.

POST /push (webhook): receive asynchronous payment status updates from the PSP. This endpoint handles webhook callbacks and updates the transaction status in commercetools. See REST endpoints & webhooks for how each provider verifies webhook authenticity.

A payment provider may also expose:

GET /redirect: handle customer redirects back from the PSP after completing payment.

POST /validate-apple-pay-session: validate an Apple Pay merchant session for Apple Pay payments.

API contract

The payment API is defined in an OpenAPI spec at backend/packages/payment-api/payment-api.yaml. The two primary endpoints and their types are documented below.

POST /create

Starts a payment transaction and returns a redirect URL for the customer to complete payment at the PSP.

Request body: Transaction

FieldTypeRequiredDescription
amountPriceyesTransaction amount
customerobjectno{ ipAddress: string } - IPv4 or IPv6
orderNumberstringyesHuman-readable order number
orderIdstring (UUID)yescommercetools order ID
paymentIdstring (UUID)yescommercetools payment ID
paymentMethodstringyesPayment method code
paymentMethodArgsobjectnoProvider-specific arguments
successUrlstring (URL)yesRedirect after successful payment
failureUrlstring (URL)yesRedirect after failed payment

Response body: TransactionResponse

FieldTypeDescription
statusstringTransaction status
payload.idstring (UUID)Transaction identifier
payload.redirectURLstring (URL)Customer redirect URL

POST /payment-methods

Returns the payment methods available for the given context (cart, locale, country).

Request body: PaymentMethodArgs

FieldTypeRequiredDescription
cartIdstring (UUID)noCart to check methods for
orderIdstring (UUID)noOrder to check methods for
currencystringyese.g. EUR, USD
countrystringyese.g. NL, DE
localestringyese.g. en-GB, nl-NL
devicestringnoweb, ios, or android

Response body: PaymentMethod[]

FieldTypeDescription
idstringMethod identifier
localizedNamestringDisplay name for the requested locale
providerstringPSP provider key
optionsarraySub-options, each with id and name

Shared types

Price

FieldTypeDescription
currencystringISO 4217 currency code
centAmountnumber (integer format)Amount in the smallest currency unit