Home » Free ACP Payments Module » Configuration

Configuration Reference: config.json and Environment Variables

The ACP Payment Module splits configuration along one bright line: non-secret settings live in a JSON file you can commit to version control, and secrets only ever come from environment variables, never a committed file. The config file selects your catalog source, storage backend, currency, TTLs, URLs, and feed details, while the environment carries Stripe keys, the ACP bearer token, and webhook secrets. This page documents every key and variable, with defaults and the reasoning behind them.

How Configuration Loads

On startup the server reads the file at ./config.json, or the path in the COMMERCE_CONFIG environment variable if set. The file is parsed and validated against a strict schema, and a missing file, invalid JSON, or an out-of-range value stops startup with a specific error message rather than booting a half-configured store. Relative paths inside the file, like a bundled catalog path, resolve relative to the config file's own directory, so the file behaves the same no matter which directory you launch from. Embedders skip the file entirely if they prefer, every option below maps to a constructor argument in the library, and the file format is simply the reference server's way of wiring the same objects.

Top-Level Settings

currency (string, default "usd"). Three-letter ISO 4217 code for the store. The catalog file declares its own currency too, and the catalog's value is what carts and sessions actually price in, keep them consistent.

cartTtlSeconds (integer, default 3600). How long an idle cart lives before expiring. Carts are conversational scratch space, an hour is generous for a chat session, and expired carts return a clean not-found error that tells the agent to start fresh.

sessionTtlSeconds (integer, defaults to cartTtlSeconds). Checkout sessions can be given a longer life than carts, useful because a session may be waiting on a human to open a hosted payment page. Completed sessions also age out on this clock, which is part of the module's store-nothing posture.

The catalog Block

Selects where products come from. Three types are supported, with type-specific fields:

"catalog": { "type": "bundled", "path": "./products.json", "cacheTtlSeconds": 300 }

"catalog": { "type": "remoteUrl", "url": "https://yoursite.com/products.json", "cacheTtlSeconds": 300 }

"catalog": { "type": "s3", "bucket": "your-bucket", "key": "store/products.json", "region": "us-east-1", "cacheTtlSeconds": 300 }

bundled reads a local file, remoteUrl fetches over HTTPS, and s3 reads an object (and requires the optional AWS SDK package, with a clear install hint in the error if it is missing). cacheTtlSeconds controls how often the source re-reads: the bundled source defaults to re-reading every time (TTL 0), which suits development, while remote and S3 default to 300 seconds. Catalog contents and validation rules are documented in the products file reference, and driver trade-offs in storage and catalog drivers.

The storage Block

"storage": { "type": "sqlite" }

"storage": { "type": "dynamo", "region": "us-east-1", "tablePrefix": "mcp_commerce_" }

sqlite (the default) backs carts, checkout sessions, and idempotency records with better-sqlite3, in-memory unless the CART_DB, SESSION_DB, and IDEMPOTENCY_DB environment variables point at file paths. dynamo switches all three stores to DynamoDB tables named by the prefix (mcp_commerce_carts, mcp_commerce_sessions, mcp_commerce_idempotency by default), the right choice on Lambda where instance memory and local disk do not persist. The SQLite modules are lazy-loaded only when selected, so a Dynamo deployment never loads the native SQLite binary, which keeps Lambda cold starts lean and avoids architecture mismatch issues entirely.

The tax Block and Store URLs

tax.enabled (boolean, default false). When false, no tax is computed anywhere. When true and a Stripe key is present, Stripe Tax computes line-level tax as soon as a buyer address is known, and hosted Stripe Checkout pages collect a billing address and apply automatic tax themselves. Setup and behavior details are in sales tax with Stripe Tax.

successUrl and cancelUrl (URLs). Where Stripe sends the shopper after finishing or abandoning a hosted payment page. Point these at real pages on your site, a thank-you page and a checkout-canceled page.

orderWebhookUrl (URL, optional). Where completed orders are POSTed. With it unset, orders are logged and dropped by the no-op sink, fine for evaluation, wrong for production. The payload and signature are specified in the order webhook guide.

permalinkBase (URL, optional). Base for the order permalink the ACP response carries, the module builds permalinkBase/order_{session-id} style URLs that should resolve to an order status page you host.

acp.requireSignature (boolean, default false). Governs the HMAC signature check on ACP requests. With a signing secret configured in the environment, signatures are always enforced. This flag covers the misconfiguration case: set it true and requests fail closed even if the secret is accidentally missing, instead of silently skipping verification.

links (array, optional). Policy links surfaced inside every checkout session so agent platforms can show them to shoppers: entries with a type of terms_of_use, privacy_policy, or return_policy and a url. Platforms expect at least terms and privacy on real merchants, and our terms of service guide and privacy policy guide cover writing them.

The feed Block

Merchant-level fields merged into every row of the ACP product feed: seller_name, seller_url, and store_country are required for the feed to generate, with brand, target_countries, is_eligible_search, is_eligible_checkout, seller_tos, seller_privacy_policy, and productUrlBase filling out platform requirements. productUrlBase deserves a note: products without their own url get one built from this base, which keeps the feed publishable while your product pages are still thin. The feed block is optional, with it absent the /feed endpoint reports not configured and everything else works normally.

Environment Variables

Two non-secret variables control runtime shape: PORT (default 3000) and COMMERCE_CONFIG (config file path). Three select SQLite file locations when you want durable single-box storage: CART_DB, SESSION_DB, and IDEMPOTENCY_DB, each defaulting to in-memory.

The secrets, all read only from the environment:

STRIPE_SECRET_KEY. Your Stripe API key. Unset, the module runs the deterministic mock payment provider and prints a warning, no real charges are possible. Set, it enables hosted Stripe Checkout, delegated token charges, and Stripe Tax.

STRIPE_WEBHOOK_SECRET. The signing secret for your Stripe webhook endpoint. Incoming events are verified against it, and the webhook handler refuses to run without it, an unverified payment confirmation is worse than none. See the webhook setup guide.

ACP_BEARER_TOKEN. The token agent platforms present on ACP requests. Unset means the ACP endpoints reject everything, the API is closed by default and opening it is an explicit act.

ACP_SIGNING_SECRET. Optional HMAC secret for ACP request signatures, verified over the raw request body with timestamp skew checking. Configure it when your platform partner signs requests.

ORDER_WEBHOOK_SECRET. Optional HMAC secret used to sign the order payload the module sends to your systems, so your fulfillment endpoint can verify the order really came from your store.

Secrets policy: there is intentionally no way to put a key in config.json. Files get committed, copied into images, and attached to support tickets; environment variables stay in your deployment platform's secret manager. If a Stripe key has ever landed in a repository, rotate it, our data protection guide covers credential hygiene for stores.

A Complete Production Example

{
  "currency": "usd",
  "cartTtlSeconds": 3600,
  "sessionTtlSeconds": 7200,
  "catalog": { "type": "s3", "bucket": "acme-store", "key": "products.json",
               "region": "us-east-1", "cacheTtlSeconds": 300 },
  "storage": { "type": "dynamo", "region": "us-east-1" },
  "tax": { "enabled": true },
  "successUrl": "https://acmetool.com/thanks",
  "cancelUrl": "https://acmetool.com/checkout-canceled",
  "orderWebhookUrl": "https://acmetool.com/hooks/order",
  "permalinkBase": "https://acmetool.com/orders",
  "acp": { "requireSignature": true },
  "links": [
    { "type": "terms_of_use", "url": "https://acmetool.com/terms" },
    { "type": "privacy_policy", "url": "https://acmetool.com/privacy" }
  ],
  "feed": {
    "brand": "Acme", "seller_name": "Acme Tools Inc",
    "seller_url": "https://acmetool.com", "store_country": "US",
    "target_countries": ["US"], "is_eligible_search": true,
    "is_eligible_checkout": true,
    "seller_tos": "https://acmetool.com/terms",
    "seller_privacy_policy": "https://acmetool.com/privacy",
    "productUrlBase": "https://acmetool.com/products"
  }
}

Paired with the five secret variables in your deployment environment, this is a complete, hardened production configuration: S3 catalog, DynamoDB state, Stripe Tax on, signatures enforced, and orders flowing to your systems.