This guide covers setup and configuration for using UCP Proxy with WooCommerce stores.
The adapter uses the WooCommerce Store API, which is included in WooCommerce 6.9+. For older versions, install the WooCommerce Blocks plugin.
Verify the Store API is available:
curl https://your-store.com/wc/store/v1/cart
# Should return cart JSON (possibly empty)Generate WooCommerce REST API keys:
- WordPress Admin → WooCommerce → Settings → Advanced → REST API
- Add Key → Read/Write permissions
- Save the Consumer Key (
ck_xxx) and Consumer Secret (cs_xxx)
For Google Pay support, install and configure WooCommerce Stripe Gateway:
- WordPress Admin → WooCommerce → Settings → Payments → Stripe
- Enable "Payment Request Buttons" for Google Pay/Apple Pay
- Note your Stripe Publishable Key (
pk_xxx)
Create a config file for local development:
cp config.example.json config.local-woo.jsonEdit config.local-woo.json:
{
"port": "8080",
"environment": "development",
"log_level": "debug",
"adapter_type": "woocommerce",
"merchant_id": "my-woo-store",
"merchant": {
"store_url": "https://shop.example.com",
"api_key": "ck_1234567890abcdef",
"api_secret": "cs_abcdef1234567890",
"policy_links": {
"privacy_policy": "https://shop.example.com/privacy",
"terms_of_service": "https://shop.example.com/terms"
},
"payment_handlers": {
"com.google.pay": [{
"id": "gpay-checkout",
"version": "2026-01-11",
"spec": "https://ucp.dev/handlers/google.pay",
"config": {
"allowed_payment_methods": [{
"type": "CARD",
"parameters": {
"allowed_auth_methods": ["PAN_ONLY", "CRYPTOGRAM_3DS"],
"allowed_card_networks": ["VISA", "MASTERCARD", "AMEX", "DISCOVER"]
},
"tokenization_specification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "stripe",
"stripe:version": "2020-08-27",
"stripe:publishableKey": "pk_test_xxx"
}
}
}]
}
}]
},
"escalation": {
"product_ids": [124, 456],
"custom_fields": ["_requires_disclaimer", "_age_restricted"]
}
}
}Run:
CONFIG_FILE=config.local-woo.json go run ./cmd/proxy| Variable | Required | Description |
|---|---|---|
CONFIG_FILE |
No | Path to JSON config file (skips other env vars) |
MERCHANT_ID |
Yes* | Unique identifier (used for logging, secret lookup) |
ADAPTER_TYPE |
Yes* | Must be woocommerce |
MERCHANT_STORE_URL |
Yes* | Full URL to WooCommerce store |
MERCHANT_API_KEY |
Yes* | WooCommerce Consumer Key (ck_xxx) |
MERCHANT_API_SECRET |
Yes* | WooCommerce Consumer Secret (cs_xxx) |
MERCHANT_NAME |
No | Display name for the merchant |
POLICY_LINKS |
No | JSON object of policy URLs |
PAYMENT_HANDLERS |
No | JSON object of payment handler configs |
*Not required if using CONFIG_FILE.
Store merchant configuration as a JSON secret:
{
"store_url": "https://shop.example.com",
"api_key": "ck_live_xxx",
"api_secret": "cs_live_xxx",
"merchant_name": "Example Store",
"policy_links": {
"privacy_policy": "https://shop.example.com/privacy",
"terms_of_service": "https://shop.example.com/terms",
"refund_policy": "https://shop.example.com/refunds"
},
"payment_handlers": {
"com.google.pay": [{
"id": "gpay-checkout",
"version": "2026-01-11",
"spec": "https://ucp.dev/handlers/google.pay",
"config": {
"allowed_payment_methods": [{
"type": "CARD",
"parameters": {
"allowed_auth_methods": ["PAN_ONLY", "CRYPTOGRAM_3DS"],
"allowed_card_networks": ["VISA", "MASTERCARD"]
},
"tokenization_specification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "stripe",
"stripe:publishableKey": "pk_live_xxx"
}
}
}]
}
}]
}
}Create the secret:
echo '{"store_url":"..."}' | gcloud secrets create my-woo-store --data-file=-Run in production:
export ENVIRONMENT=production
export GCP_PROJECT=my-gcp-project
export MERCHANT_ID=my-woo-store
export ADAPTER_TYPE=woocommerce
go run ./cmd/proxy┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐
│ AI Agent │ UCP │ UCP Proxy │ Store │ WooCommerce │
│ │◄──────►│ │◄──────►│ │
│ │ │ WooCommerce │ API │ ┌────────────────┐ │
│ │ │ Adapter │ │ │ Store API │ │
└──────────────┘ └──────────────┘ │ │ /wc/store/v1 │ │
│ └────────────────┘ │
│ ┌────────────────┐ │
│ │ Stripe Plugin │ │
│ │ (payments) │ │
│ └────────────────┘ │
└──────────────────────┘
WooCommerce Store API uses a Cart-Token header to maintain cart state without cookies. The proxy encodes this token in the checkout ID, enabling stateless operation.
┌─────────┐ ┌───────────┐ ┌─────────────┐
│ Agent │ │ Proxy │ │ WooCommerce │
└────┬────┘ └─────┬─────┘ └──────┬──────┘
│ │ │
│ create_checkout │ │
│ {line_items: [...]} │ │
│──────────────────────────────►│ │
│ │ │
│ │ POST /wc/store/v1/cart/add-item
│ │─────────────────────────────────►
│ │ │
│ │ Cart-Token: abc123 │
│ │◄─────────────────────────────────
│ │ │
│ │ POST /wc/store/v1/checkout │
│ │ Cart-Token: abc123 │
│ │─────────────────────────────────►
│ │ │
│ │ {order_id: 456, ...} │
│ │◄─────────────────────────────────
│ │ │
│ checkout.id = │ │
│ "gid://shop.com/456:abc123" │ │
│◄──────────────────────────────│ │
│ │ │
│ update_checkout │ │
│ {id: "gid://.../456:abc123"} │ │
│──────────────────────────────►│ │
│ │ │
│ │ (extracts abc123 from ID) │
│ │ POST /wc/store/v1/checkout │
│ │ Cart-Token: abc123 │
│ │─────────────────────────────────►
The checkout ID format gid://{domain}/Checkout/{order_id}:{cart_token} encodes the cart token, so subsequent requests can authenticate with WooCommerce without the proxy maintaining any state.
| Endpoint | Method | Purpose |
|---|---|---|
/wc/store/v1/cart/add-item |
POST | Add products to cart |
/wc/store/v1/cart/apply-coupon |
POST | Apply discount codes |
/wc/store/v1/cart/select-shipping-rate |
POST | Select shipping method |
/wc/store/v1/checkout |
GET | Get checkout state |
/wc/store/v1/checkout |
POST | Create/update checkout, submit payment |
| Handler | Description | Requirements |
|---|---|---|
google.pay |
Google Pay via Stripe | Stripe plugin + publishable key |
redirect |
Browser-based fallback | None (always available) |
When an agent provides a Stripe PaymentMethod token from Google Pay:
{
"payment": {
"selected_instrument_id": "instr_1",
"instruments": [{
"id": "instr_1",
"handler_id": "google.pay",
"type": "card",
"credential": {
"type": "stripe.payment_method",
"token": "pm_1234567890"
}
}]
}
}The adapter passes this to WooCommerce Stripe:
{
"payment_method": "stripe",
"payment_data": [
{"key": "wc-stripe-payment-method", "value": "pm_1234567890"},
{"key": "wc-stripe-is-deferred-intent", "value": "true"}
]
}When 3DS authentication is required, WooCommerce returns a redirect URL:
{
"payment_result": {
"payment_status": "pending",
"redirect_url": "https://hooks.stripe.com/3d_secure/..."
}
}The proxy returns this as an escalation:
{
"status": "requires_escalation",
"continue_url": "https://hooks.stripe.com/3d_secure/...",
"messages": [{
"type": "info",
"code": "3DS_REQUIRED",
"content": "Payment requires 3D Secure authentication"
}]
}The agent should present continue_url to the user for completing authentication in a browser.
Some products require browser checkout due to legal disclaimers, age verification, or custom input fields. Configure escalation triggers in the merchant config:
{
"escalation": {
"product_ids": [124, 456],
"custom_fields": ["_requires_disclaimer", "_age_restricted"]
}
}| Field | Description |
|---|---|
product_ids |
Product IDs that always require browser checkout |
custom_fields |
Meta keys that trigger escalation when present on cart item |
When a cart contains matching products:
- Create/Get/Update: Returns
status: requires_escalationwith full cart data (informational) - Complete: Blocks payment processing, returns escalation response
{
"status": "requires_escalation",
"continue_url": "https://shop.example.com/checkout-link/?products=124:1",
"messages": [{
"type": "error",
"code": "ESCALATION_REQUIRED",
"content": "Products require additional buyer input: Custom Map. Complete checkout in browser.",
"severity": "escalation"
}]
}The continue_url uses WooCommerce's shareable checkout URL format, pre-populating the cart with the same products.
Note: custom_fields requires the merchant to expose product meta via the woocommerce_store_api_add_to_cart_data PHP filter. product_ids works without any merchant-side changes.
If the payment method isn't supported or the agent requests the redirect handler, the checkout returns:
{
"status": "requires_escalation",
"continue_url": "https://shop.example.com/checkout/order-pay/456/?key=wc_order_xxx",
"messages": [{
"type": "info",
"code": "ESCALATION_REQUIRED",
"content": "Payment requires browser checkout"
}]
}Symptom: 401 Unauthorized or 403 Forbidden
Causes:
- Invalid API keys - verify
ck_andcs_values - Wrong permissions - keys need Read/Write access
- HTTPS required - WooCommerce may require HTTPS for API access
Test credentials:
curl -u ck_xxx:cs_xxx https://your-store.com/wc/store/v1/cartSymptom: checkout not found on get/update operations
Causes:
- Cart expired - WooCommerce carts expire after ~48 hours
- Cart cleared - user may have completed checkout via web
- Token invalid - malformed checkout ID
Debug: Check if the cart token is being extracted correctly from the checkout ID.
Symptom: Shipping options not appearing or selection fails
Causes:
- Shipping zones not configured for the address
- Product marked as "virtual" (no shipping required)
- Missing or invalid shipping address
Check WooCommerce:
- WooCommerce → Settings → Shipping → Shipping zones
- Ensure zones cover the target countries
Symptom: Payment fails with upstream error
Causes:
- Stripe not configured as payment gateway
- Payment method token expired
- Card declined by Stripe
Check WooCommerce:
- WooCommerce → Settings → Payments → Stripe → Enable
- Enable "Payment Request Buttons" for Google Pay
Symptom: 404 Not Found on /wc/store/v1/*
Causes:
- WooCommerce version < 6.9 without Blocks plugin
- Permalinks set to "Plain" (breaks REST API routing)
Fix:
- Update WooCommerce, or install WooCommerce Blocks
- WordPress → Settings → Permalinks → any option except "Plain"
| UCP Field | WooCommerce Field |
|---|---|
line_items[].item.id |
items[].id |
line_items[].item.title |
items[].name |
line_items[].item.price |
items[].prices.price (parsed to cents) |
totals[].amount |
totals.total_* (parsed to cents) |
shipping_address |
shipping_address |
billing_address |
billing_address |
buyer.email |
billing_address.email |
| WooCommerce Status | UCP Status |
|---|---|
checkout-draft |
not_ready_for_payment |
pending |
ready_for_payment |
processing |
completed |
on-hold |
requires_escalation |
completed |
completed |
cancelled |
canceled |
failed |
unrecoverable_errors |