Protocols

ACP checkout

The five ACP checkout operations mapped onto your existing checkout API.

The Agentic Commerce Protocol checkout service, pinned to 2026-04-17 and experimental. Five operations, each mapped to one resource that fronts the merchant's existing checkout API.

ACP operationRouteResource
createCheckoutSessionPOST /acp/checkout_sessionsacp_checkout_create
updateCheckoutSessionPOST /acp/checkout_sessions/{id}acp_checkout_update
getCheckoutSessionGET /acp/checkout_sessions/{id}acp_checkout_get
completeCheckoutSessionPOST …/{id}/completeacp_checkout_complete
cancelCheckoutSessionPOST …/{id}/cancelacp_checkout_cancel
examples/acp-checkout/config.yamlyaml
version: 1

merchant:
  id: acp-checkout-example
  name: ACP Checkout Example
  publicBaseUrl: ${GATEWAY_PUBLIC_BASE_URL:-http://localhost:8080}

server:
  port: ${GATEWAY_PORT:-8080}
  host: 0.0.0.0

storage:
  receipts:
    driver: sqlite
    path: ${RECEIPT_STORE_PATH:-./data/receipts.sqlite}

protocols:
  # Off: this gateway serves ACP, not generic HTTP resource routes.
  http:
    enabled: false
  mcp:
    enabled: false
    mountPath: /mcp
  acp:
    enabled: true
    mountPath: /acp
    auth:
      type: bearer
      token: ${ACP_BEARER_TOKEN:-local-development-acp-token}
    idempotency:
      # Its own database — never shared with receipts or x402 replay.
      path: ${ACP_IDEMPOTENCY_PATH:-./data/acp-idempotency.sqlite}
      retentionHours: 24
    checkout:
      operations:
        createCheckoutSession: acp_checkout_create
        updateCheckoutSession: acp_checkout_update
        getCheckoutSession: acp_checkout_get
        completeCheckoutSession: acp_checkout_complete
        cancelCheckoutSession: acp_checkout_cancel
    discovery:
      supportedCurrencies: [usd]
      supportedLocales: [en-US]

# Every ACP checkout resource is free with no payments: ACP checkout carries
# the merchant's own purchase payment in `payment_data`.
resources:
  acp_checkout_create:
    name: Create checkout session
    description: ACP createCheckoutSession. Answers 201 with a checkout session.
    input:
      type: object
      properties:
        body: { type: object }
      required: [body]
      additionalProperties: false
    backend:
      type: http
      method: POST
      url: ${MERCHANT_API_BASE_URL:-http://localhost:3000}/checkout_sessions
      inputBindings:
        body: body
      timeoutMs: 10000
    pricing:
      type: free
    expose: [acp]

  acp_checkout_update:
    name: Update checkout session
    description: ACP updateCheckoutSession.
    input:
      type: object
      properties:
        path:
          type: object
          properties:
            checkout_session_id: { type: string }
          required: [checkout_session_id]
          additionalProperties: false
        body: { type: object }
      required: [path]
      additionalProperties: false
    backend:
      type: http
      method: POST
      url: ${MERCHANT_API_BASE_URL:-http://localhost:3000}/checkout_sessions/{checkout_session_id}
      inputBindings:
        path: path
        body: body
      timeoutMs: 10000
    pricing:
      type: free
    expose: [acp]

  acp_checkout_get:
    name: Retrieve checkout session
    description: ACP getCheckoutSession.
    input:
      type: object
      properties:
        path:
          type: object
          properties:
            checkout_session_id: { type: string }
          required: [checkout_session_id]
          additionalProperties: false
      required: [path]
      additionalProperties: false
    backend:
      type: http
      method: GET
      url: ${MERCHANT_API_BASE_URL:-http://localhost:3000}/checkout_sessions/{checkout_session_id}
      inputBindings:
        path: path
      timeoutMs: 10000
    pricing:
      type: free
    expose: [acp]

  acp_checkout_complete:
    name: Complete checkout session
    description: ACP completeCheckoutSession. `payment_data` reaches the backend as ordinary business input.
    input:
      type: object
      properties:
        path:
          type: object
          properties:
            checkout_session_id: { type: string }
          required: [checkout_session_id]
          additionalProperties: false
        body: { type: object }
      required: [path]
      additionalProperties: false
    backend:
      type: http
      method: POST
      url: ${MERCHANT_API_BASE_URL:-http://localhost:3000}/checkout_sessions/{checkout_session_id}/complete
      inputBindings:
        path: path
        body: body
      timeoutMs: 15000
    pricing:
      type: free
    expose: [acp]

  acp_checkout_cancel:
    name: Cancel checkout session
    description: ACP cancelCheckoutSession.
    input:
      type: object
      properties:
        path:
          type: object
          properties:
            checkout_session_id: { type: string }
          required: [checkout_session_id]
          additionalProperties: false
        body: { type: object }
      required: [path]
      additionalProperties: false
    backend:
      type: http
      method: POST
      url: ${MERCHANT_API_BASE_URL:-http://localhost:3000}/checkout_sessions/{checkout_session_id}/cancel
      inputBindings:
        path: path
        body: body
      timeoutMs: 10000
    pricing:
      type: free
    expose: [acp]

payments: {}
Why every resource is freeACP checkout carries the merchant's own purchase payment, in payment_data on completion. It is business input for your backend — never converted into an x402 payment — and a paid mapping is refused at load.

Run it

This example assumes a backend that already implements the ACP checkout shapes at ${MERCHANT_API_BASE_URL}/checkout_sessions…; point it at yours.

bash
AGENT_COMMERCE_CONFIG=examples/acp-checkout/config.yaml npx tsx src/gateway/main.ts

# in another terminal
npm run agent-commerce -- validate --config examples/acp-checkout/config.yaml
npm run agent-commerce -- doctor --config examples/acp-checkout/config.yaml

Call it

bash
curl -s http://localhost:8080/.well-known/acp.json

curl -s http://localhost:8080/acp/checkout_sessions \
  -H "Authorization: Bearer local-development-acp-token" \
  -H "API-Version: 2026-04-17" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"line_items":[{"id":"item_123"}],"currency":"usd","capabilities":{}}'

Retrying with the same Idempotency-Key replays the stored answer with Idempotent-Replayed: true and never reaches the merchant twice; the same key with a different body is a 422. Wire details: ACP.

Source: examples/acp-checkout