A TypeScript + Express service that connects WooCommerce stores to the Agentic Commerce Protocol (ACP), enabling AI agents to browse products, manage checkouts, and process payments.
- Product Feed - Standardizes WooCommerce products for AI agents
- Checkout Flow - Create, update, and finalize orders
- Payment Processing - Confirm payments and update order status
- API Key Auth - Secure all endpoints with bearer token authentication
# Install
pnpm install
# Configure (see below)
cp .env.example .env
# Edit .env with your WooCommerce credentials
# Run
pnpm dev
# Test
curl http://localhost:3000/health-
Generate API Keys in WooCommerce Admin:
- Go to: WooCommerce โ Settings โ Advanced โ REST API
- Click "Add Key"
- Permissions: Read/Write
- Copy Consumer Key and Consumer Secret
-
Secure Connection to WooCommerce:
- Requires asecure https connection to woocommerce site
- ssl enabled + domain attached
-
Wordpress Permalinks:
- Wordpress console -> Settings -> Permlinks: Settings should be anthing other than "Plain".
- Chose "Post name" ideally.
-
Quick Test:
- Test product feed using "https://your-site-url/wp-json" to ensure setup is accessible.
- Key Scopes:
- Ensure keys have Read/Write permissions for Products and Orders
- Read access: Browse products, get order details
- Write access: Create/update orders, process payments
Don't have a WooCommerce store? Use our public test store to try ACP Bridge immediately.
๐ See test-store/ folder for:
- Pre-configured demo credentials
- Ready-to-use .env file
- Example API calls with demo data
Quick start with demo store:
cp test-store/.env.demo .env.local
pnpm install
pnpm devThen try the example requests in test-store/README.md.
Note: Demo credentials are public and rate-limited. For production use, set up your own WooCommerce store (see above).
- Configure Environment (
.env):# Server PORT=3000 # WooCommerce WOO_BASE_URL=https://your-store.com WOO_CONSUMER_KEY=ck_xxxxxxxxxxxxx WOO_CONSUMER_SECRET=cs_xxxxxxxxxxxxx # Security AGENT_API_KEYS=agent-key-1,agent-key-2
- Start Server:
pnpm dev
All endpoints require Authorization: Bearer <your-agent-key> header.
| Endpoint | Method | Purpose |
|---|---|---|
/health |
GET | Health check (no auth) |
/acp/feed |
GET | Browse products |
/acp/checkout/sessions |
POST | Create order |
/acp/checkout/sessions/:id |
PATCH | Update order |
/acp/checkout/sessions/:id/complete |
POST | Finalize order |
/acp/payments/confirm |
POST | Process payment |
๐ Full API Specification: openapi/acp-proxy.yaml
GET /acp/feed - Browse Products
Query Parameters:
page(number, optional): Page number (default: 1)per_page(number, optional): Items per page (default: 50, max: 100)category(string, optional): Filter by category IDq(string, optional): Search query
Response:
{
"products": [
{
"id": "107",
"title": "Product Name",
"description": "Product description",
"price": "19.99",
"currency": "USD",
"availability": "in_stock",
"url": "https://store.com/product/...",
"images": [{"url": "https://...", "alt": "..."}],
"category": "Electronics",
"sku": "PROD-123"
}
],
"pagination": {
"page": 1,
"per_page": 50,
"total": 42
}
}POST /acp/checkout/sessions - Create Order
Request Body:
{
"items": [
{
"product_id": 107,
"quantity": 2
}
],
"shipping_address": {
"first_name": "John",
"last_name": "Doe",
"address_1": "123 Main St",
"city": "New York",
"state": "NY",
"postcode": "10001",
"country": "US"
},
"billing_address": { /* same format as shipping */ }
}Response:
{
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"order_id": 128,
"status": "draft",
"total": "39.98",
"currency": "USD"
}Notes:
shipping_addressandbilling_addressare optional- Either
product_idorskurequired for each item session_idis a UUID for tracking the checkout session
PATCH /acp/checkout/sessions/:id - Update Order
Request Body (all fields optional, but at least one required):
{
"items": [
{
"product_id": 107,
"quantity": 3
}
],
"shipping_address": { /* address object */ },
"billing_address": { /* address object */ }
}Response:
{
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"order_id": 128,
"status": "draft",
"total": "59.97",
"currency": "USD",
"items": [...]
}Notes:
- Only works when order status is
draft(pending state) - Returns 409 if order already finalized
POST /acp/checkout/sessions/:id/complete - Finalize Order
Request Body: None
Response:
{
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"order_id": 128,
"status": "pending_payment",
"total": "59.97",
"currency": "USD"
}Notes:
- Locks order for payment (prevents further updates)
- Validates inventory availability
- Idempotent (safe to retry)
POST /acp/payments/confirm - Process Payment
Request Body:
{
"order_id": 128,
"payment_token": "tok_visa_4242",
"provider_hint": "stripe"
}Response:
{
"status": "paid",
"receipt_reference": "tok_visa_4242"
}Status Values:
paid- Payment successfulpending- Payment processingfailed- Payment failed
Notes:
provider_hintis optional (e.g., "stripe", "paypal")- Order must be in
pending_paymentstatus
All request bodies are validated with strict Zod schemas:
- Unknown fields rejected (strict mode)
- Type validation enforced
- Required fields checked
Validation Error Response:
{
"error": {
"code": "validation_error",
"message": "Request validation failed",
"details": {
"issues": [
{
"path": ["items", 0, "quantity"],
"message": "Quantity must be a positive integer"
}
]
}
}
}All errors return a consistent envelope format:
| Error Code | HTTP Status | Description |
|---|---|---|
validation_error |
400 | Request body validation failed |
invalid_request |
400 | Malformed request or business rule violation |
missing_auth_header |
401 | Authorization header missing |
unauthorized |
401 | Invalid API key |
not_found |
404 | Resource not found (order, product, session) |
out_of_stock |
409 | Product inventory insufficient |
order_finalized |
409 | Cannot update finalized order |
rate_limited |
429 | Too many requests |
upstream_error |
500 | WooCommerce API error |
Error Format:
{
"error": {
"code": "error_code_here",
"message": "Human-readable error message",
"details": {}
}
}๐ Complete Error Reference: See docs/ERROR_CODES.md for detailed examples
| Endpoint | Purpose | Use Case |
|---|---|---|
GET /health |
Liveness probe | Returns 200 if server is running (no auth required) |
GET /ready |
Readiness probe | Returns 200 if configured, 503 if config invalid |
Health Response:
{"status": "ok"}Ready Response (success):
{"status": "ready"}Ready Response (not configured):
{"status": "not_configured"}Use /ready for Kubernetes readiness probes and load balancer health checks.
- No idempotency token storage - Agents must handle deduplication for create/payment operations
- Sessions in-memory only - Session state lost on server restart
- Best-effort only -
Idempotency-Keyheader passed through to WooCommerce but not enforced
Recommended:
- Store
order_idfrom create response for long-term tracking - Implement retry logic with exponential backoff for failed payments
- Use
GET /acp/checkout/sessions/:id/completeidempotent behavior when possible
๐ฎ v0.2 Roadmap: Full idempotency token storage with Redis/database backend
We provide an interactive shopping CLI for testing:
./tests/scripts/shop-cli.shAvailable Commands:
/browse- Browse products/search <query>- Search products/add <id> <qty>- Add to cart/checkout- Create order/complete- Finalize order/pay- Process payment/help- Show all commands
Example Flow:
๐ Shop > /browse
๐ Shop > /add 107 2
๐ Shop > /checkout
๐ Order #128 > /complete
๐ Order #128 > /pay
๐ PAYMENT SUCCESSFUL!
curl http://localhost:3000/healthcurl http://localhost:3000/acp/feed \
-H "Authorization: Bearer agent-key-1"curl -X POST http://localhost:3000/acp/checkout/sessions \
-H "Authorization: Bearer agent-key-1" \
-H "Content-Type: application/json" \
-d '{"items": [{"product_id": 107, "quantity": 2}]}'# Replace SESSION_ID with session_id from create response
curl -X PATCH http://localhost:3000/acp/checkout/sessions/SESSION_ID \
-H "Authorization: Bearer agent-key-1" \
-H "Content-Type: application/json" \
-d '{"items": [{"product_id": 107, "quantity": 3}]}'# Replace SESSION_ID with session_id from create response
curl -X POST http://localhost:3000/acp/checkout/sessions/SESSION_ID/complete \
-H "Authorization: Bearer agent-key-1"curl -X POST http://localhost:3000/acp/payments/confirm \
-H "Authorization: Bearer agent-key-1" \
-H "Content-Type: application/json" \
-d '{
"order_id": 128,
"payment_token": "tok_visa_4242",
"provider_hint": "stripe"
}'๐ Complete Testing Guide: See TESTING.md for comprehensive smoke test checklist
| Command | Purpose |
|---|---|
pnpm dev |
Start dev server with hot reload |
pnpm build |
Build for production |
pnpm test |
Run all tests |
pnpm lint |
Check code style |
Server won't start
- Check
.envfile exists and has all required variables - Verify WooCommerce credentials are correct
- Check port 3000 is available:
lsof -ti:3000
401 Unauthorized
- Verify
Authorization: Bearer <key>header is present - Check key is listed in
ALLOWED_AGENT_KEYS
WooCommerce errors
- Verify
WOO_BASE_URLis correct (include https://) - Test WooCommerce API directly:
curl <WOO_BASE_URL>/wp-json/wc/v3/products - Check WooCommerce API keys have Read/Write permissions
Product not found
- Browse products first to get valid product IDs
- Ensure product is published in WooCommerce
- Check stock status (out-of-stock products may cause errors)
Payment fails
- Order must be in
pending_paymentstatus (use/completefirst) - Check order exists and hasn't been cancelled
- Verify order ID is correct
Validation errors (400)
- Check request body matches schema (see API Reference above)
- Ensure all required fields present (items, quantity, addresses)
- Verify field types (quantity must be integer, country must be 2-char ISO code)
- Remove unknown fields (strict validation enabled)
Session not found (404)
- Session IDs expire on server restart (in-memory storage in v0.1)
- Use
order_idfrom response to track long-term - Double-check session_id matches response from create/update
- Node.js 18+
- pnpm
- WooCommerce store with REST API enabled
jq(for CLI testing):brew install jq
This project is licensed under the Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) License โ see the LICENSE file for details.