Checkout

Overview

Checkout is a whitelabel order and checkout layer: an API for purchase orders, customers and checkout transactions, and a brandable Vue 3 checkout page. It validates the order (currency, tax, validity window, required consents) before it records the buyer’s checkout transaction.

Current scope. Checkout records the checkout transaction as PENDING and returns nextAction: NONE. It does not call the Payment Gateway yet, and it does not publish events yet.

Capabilities

Capability Description
Purchase orders Items, currency, tax, an optional customer and an optional validity window (startsAt, endsAt).
Customers Create, read and update customer records.
Checkout transactions A transaction per checkout, with billing and shipping details, consents and the chosen payment method.
Validation Currency, tax rate, time range, extras and required consents are checked before a transaction is created.
Multi-tenant Tenant and scopes come from the trusted gateway headers; every query is tenant-scoped.
Checkout page A Vue 3 UI configured at runtime through env.json, with i18n.

Architecture

Checkout sits behind the API Gateway. The API stores orders in PostgreSQL and asks the central policy engine (Cerbos) whether the caller may act on a resource.

sequenceDiagram
    autonumber
    participant B as Buyer / storefront
    participant GW as API Gateway
    participant CO as Checkout API
    participant DB as PostgreSQL

    B->>GW: POST /checkout/api/v1/purchase-orders
    GW->>CO: request + X-Auth-* headers
    CO->>DB: store order
    CO-->>B: 201 PurchaseOrder
    B->>GW: POST /purchase-orders/{id}/checkout
    GW->>CO: request + X-Auth-* headers
    CO->>CO: validate window and consents
    CO->>DB: store CheckoutTransaction (PENDING)
    CO-->>B: transaction + nextAction NONE

Quick Start

Checkout is an optional module. Install the platform with the BYO profile of the installer and answer yes to “Enable Checkout”, or run it in the full local ecosystem.

Install with Helm

With a cluster and a PostgreSQL database, install the chart (API and checkout page) and point it at the database:

helm repo add labs64io https://labs64.github.io/labs64.io-helm-charts
helm repo update

helm install my-checkout labs64io/checkout -n labs64io --create-namespace \
  --set global.postgresql.host=postgres.mycompany.internal

Database credentials go in a Kubernetes Secret (see the chart’s values), and behind the gateway Checkout also needs the central policy engine (the authz-pdp chart). See Deploy to your Kubernetes cluster and the chart on Artifact Hub.

Try the API with Docker

To try the API without a cluster, run the published image next to PostgreSQL and the policy engine. Only Docker and Git are needed. Authorization policies are generated from the API contract by the build, so the first step produces them once inside a Maven container; the second step runs the published image.

git clone https://github.com/Labs64/labs64.io-checkout.git && cd labs64.io-checkout

docker run --rm -v "$PWD":/src -w /src/checkout-be maven:3.9-eclipse-temurin-25 \
  mvn -B -q -DskipTests package                      # generates the authorization policies

docker compose -f docker-compose.images.yml up -d    # PostgreSQL, Cerbos and the Checkout API

Create an order and check out. The headers stand in for the ones the API Gateway adds after authenticating a caller:

api() { curl -s -H "X-Auth-User: demo-user" -H "X-Auth-Tenant: demo" -H "X-Request-ID: demo" \
  -H "X-Auth-Scopes: purchase-order:read,purchase-order:write,purchase-order:checkout,checkout-transaction:read" \
  -H "Content-Type: application/json" "$@"; }

# 1. A purchase order: one item, 30.00 USD
ORDER=$(api -X POST localhost:8080/purchase-orders -d '{
  "currency": "USD",
  "items": [{"name": "Widget Pro", "sku": "WIDGET-PRO", "quantity": 1, "price": 3000}]
}' | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)

# 2. The buyer checks out
api -X POST localhost:8080/purchase-orders/$ORDER/checkout -d '{
  "paymentMethod": "STRIPE", "consents": {}, "extra": {},
  "billingInfo": {"firstName": "Jane", "lastName": "Doe", "email": "jane.doe@example.com",
                  "country": "US", "city": "San Francisco", "address1": "123 Market St", "postalCode": "94105"}
}' | grep -o '"status":"[A-Z]*"\|"nextAction":{"type":"[A-Z]*"'
"status":"PENDING"
"nextAction":{"type":"NONE"

The order is validated and a checkout transaction exists in PENDING. Swagger UI is at http://localhost:8080/swagger-ui.html. Clean up with docker compose -f docker-compose.images.yml down -v.

This is an evaluation setup without an API Gateway: do not expose port 8080. The checkout page needs the gateway in front of the API, so it comes with the installer’s BYO profile or the full local ecosystem.

Build from source

Needs Docker with Compose v2, JDK 25 and Maven 3.6.3+, and Node for the page:

cd checkout-be
mvn -B clean package -DskipTests                       # build the API and generate the policies
docker compose -f docker-compose.dev.yml up -d         # PostgreSQL, Cerbos and the API from your jar

cd ../checkout-fe
npm install && npm run dev                              # the checkout page on http://localhost:5173

The repository’s AGENTS.md describes the layout, commands and tests; the Contributing guide covers the workflow.

Configuration

Variable Description Default
SPRING_DATASOURCE_URL PostgreSQL JDBC URL. none
SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD PostgreSQL credentials. none
SPRING_FLYWAY_ENABLED Apply database migrations at start. true
LABS64_AUTH_AUTHZ_PDPADDRESS Central Cerbos policy engine (gRPC), required because order access is checked against it. none

The checkout page reads /config/env.json at runtime. Mount your own to set the API address:

{ "VITE_API_URL": "https://gateway.example.com/checkout/api/v1" }

REST APIs

All paths are relative to the service; behind the API Gateway they are served under /checkout/api/v1.

Endpoint Method Scope Description
/customers GET, POST customer:read, customer:write List or create customers.
/customers/{id} GET, PATCH customer:read, customer:write Read or update a customer.
/purchase-orders GET, POST purchase-order:read, purchase-order:write List or create purchase orders.
/purchase-orders/{id} GET, PATCH purchase-order:read, purchase-order:write Read or update a purchase order.
/purchase-orders/{id}/checkout POST purchase-order:checkout Create the checkout transaction for an order.
/checkout-transactions GET checkout-transaction:read List checkout transactions.
/checkout-transactions/{id} GET checkout-transaction:read Read one transaction.

The OpenAPI contract is the source of truth: openapi-checkout-v1.yaml.

Events

Checkout does not publish events yet. When it does, they will be delivered to AuditFlow over its HTTP API as a service principal, like the Payment Gateway’s.

Examples

Creating an order and checking out

POST /purchase-orders
{
  "currency": "USD",
  "items": [{ "name": "Widget Pro", "sku": "WIDGET-PRO", "quantity": 1, "price": 3000 }]
}

POST /purchase-orders/{id}/checkout
{
  "paymentMethod": "STRIPE",
  "consents": {},
  "extra": {},
  "billingInfo": { "firstName": "Jane", "lastName": "Doe", "email": "jane.doe@example.com",
                   "country": "US", "city": "San Francisco", "address1": "123 Market St", "postalCode": "94105" }
}

The response carries the transaction (status PENDING) and nextAction (NONE). Send consents and extra explicitly: leaving them out currently returns 500.

Operations

Checkout needs PostgreSQL for its state and a reachable Cerbos policy engine whose policies were generated from the same API contract version. Back up the database regularly and monitor connection pool metrics through Actuator.

Troubleshooting

Symptom Cause Resolution
The service exits at start with QueryPlanner missing The policy engine is not configured Set LABS64_AUTH_AUTHZ_PDPADDRESS and make Cerbos reachable; authorization cannot be switched off for this module.
401 Unauthorized on every call Trusted X-Auth-* headers missing Call through the API Gateway, or send X-Auth-User, X-Auth-Tenant, X-Auth-Scopes (comma-separated) and X-Request-ID.
403 from Cerbos on a valid token Policies do not match the running version Regenerate the policies from the same checkout of the contract (mvn package) and reload the policy engine.
500 on /checkout consents or extra omitted Send both, using {} when there is nothing to record.