Skip to content
API reference

OrderCore API Guide

REST API for order creation, sync, and webhooks. Authenticate with an API key, create idempotent orders, and receive signed webhooks. The full first-order flow is three calls: GET /healthPOST /v1/onboarding/demo-dataPOST /v1/orders.

This guide covers the public API surface only. Machine-readable spec: /openapi.yaml (import into GPT Actions, Claude tools, Postman, or an OpenAPI codegen). Full guide as plain markdown for AI assistants: /docs.md. Gateway plugin packages: /downloads. New here? Run the 5-minute agent commerce demo (offline, no signup) or start with get started.

Base URLs

  • Production: https://api.ordercore.ai
  • Demo: https://demo-api.ordercore.ai

Authentication

Send your API key on every request:

  • X-API-Key: <your_key>
  • or Authorization: Bearer <your_key>
terminal
curl -H "X-API-Key: oc_live_..." https://api.ordercore.ai/v1/account/auth

Idempotency

For create operations include:

  • Header: Idempotency-Key
  • or body field: idempotency_key

Pagination

List endpoints accept page and per_page (default 20, max 100).

Create your first order (First Success)

Use this same flow everywhere (docs, tutorial, and get-started):

  1. Check the API is up: GET /health — no API key needed
  2. Seed a demo catalog: POST /v1/onboarding/demo-data — creates demo products, SKUs, inventory, prices and a sample customer
  3. Create your first order: POST /v1/orders — idempotent, so an agent retry is safe
  4. Confirm the order (optional): POST /v1/orders/{orderID}/confirm — moves it pendingconfirmed

After this flow you will have:

  • a real order in the system
  • a working API call
  • a clear go/no-go decision

Built for real systems:

  • idempotent order creation
  • retry-safe APIs
  • webhook-driven integrations

No store, no UI, no checkout flow needed. Just API.

You need an oc_live_... API key for this flow — it arrives with the 3-day trial, or request a first key without checkout.
terminal
export API_KEY="oc_live_..."

# 1) check the API is up (no key needed)
curl -sS https://api.ordercore.ai/health

# 2) seed demo catalog / inventory / pricing
SEED_JSON="$(curl -sS -X POST https://api.ordercore.ai/v1/onboarding/demo-data \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}')"

# 3) resolve sample identifiers from the seed response
CUSTOMER_ID="$(printf '%s' "$SEED_JSON" | jq -r '.sample_customer_id // empty')"
SKU_ID="$(printf '%s' "$SEED_JSON" | jq -r '.sample_order_item.sku_id // empty')"

test -n "$CUSTOMER_ID" || { echo "No sample_customer_id returned by onboarding"; exit 1; }
test -n "$SKU_ID" || { echo "No sample_order_item.sku_id returned by onboarding"; exit 1; }

# 4) create your first order (idempotent — a retry returns the same order)
ORDER_JSON="$(curl -sS -X POST https://api.ordercore.ai/v1/orders \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: first-order-001" \
  -d "{\"customer_id\":\"$CUSTOMER_ID\",\"items\":[{\"sku_id\":\"$SKU_ID\",\"quantity\":1}]}")"
echo "$ORDER_JSON"

# 5) optional: confirm the order (pending -> confirmed; safe to repeat)
ORDER_ID="$(printf '%s' "$ORDER_JSON" | jq -r '.id // empty')"
curl -sS -X POST "https://api.ordercore.ai/v1/orders/$ORDER_ID/confirm" \
  -H "X-API-Key: $API_KEY"
Requires jq for onboarding response parsing.

Endpoints

The public API surface, grouped by what you are trying to do. Rows marked details have a worked request/response further down this page. The machine-readable contract is /openapi.yaml; this page is the human view of it.

Model packs for OpenAI, Claude, Gemini, DeepSeek and Grok live at /ai-integrations.

Public — no API key

Callable with no credentials. Rate-limited per IP.

GET /health

Service status. The first call in the first-order flow.

POST /bootstrap/sandbox-key

Issue a read-only sandbox key for the demo catalog. No signup, no form — the fastest way to a real authenticated response. guide

GET /direct-ai/manifest

Public Direct-AI checkout manifest: commercial and technical entry points.

GET /direct-ai/browser-config

Browser-safe checkout config, including the Stripe publishable key when one is configured.

GET /integrations/catalog

Public add-ons catalog: connectors and the UCP compatibility summary.

GET /integrations/shopify/status

Public Shopify install diagnostics (non-sensitive).

Orders

The core surface. Order creation is idempotent, so an agent retry is safe.

POST /v1/orders

Create an order. With Idempotency-Key, replaying the same key returns the original order; the same key with a changed payload returns 409. details

GET /v1/orders

List orders.

GET /v1/orders/{order_id}

Order detail.

GET /v1/orders/lookup

Look up the latest checkout session and order by merchant_reference_id.

GET /v1/orders/{order_id}/trace

Tenant-safe timeline of order creation, status events and webhook deliveries. No payloads or response bodies. details

POST /v1/orders/{order_id}/confirm

Confirm an order (pending → confirmed). Safe to repeat. details

POST /v1/orders/{order_id}/cancel

Cancel an order. details

Onboarding

Get a catalog to sell against without wiring a connector first.

POST /v1/onboarding/demo-data

Seed a demo catalog: products, SKUs, inventory, prices and a sample customer. details

POST /v1/onboarding/catalog-csv

Import a starter catalog, prices and inventory without Shopify or another connector. details

Catalog & inventory

GET /v1/products

List products. Filters: status.

POST /v1/products

Create a product.

GET /v1/products/{product_id}

Product detail.

PATCH /v1/products/{product_id}

Update a product.

DELETE /v1/products/{product_id}

Delete a product.

GET /v1/skus/{skuCode}

SKU detail.

GET /v1/inventory

List inventory. Filters: sku_id/sku_code, location_id.

POST /v1/inventory/adjust

Adjust stock.

POST /v1/inventory/reserve

Reserve stock.

POST /v1/inventory/release

Release reserved stock.

GET /v1/prices

List prices. Filters: sku_id/sku_code, price_list_code, currency, customer_id, quantity, valid_now, active_only.

Checkout (UCP)

Merchant-authenticated sessions use your API key. The /ucp/public/* mirror is for buyer-facing pages and is authorised by a short-lived checkout token instead.

GET /ucp/.well-known/ucp

UCP discovery document: version, capabilities and business profile. details

POST /ucp/checkout/sessions

Create a checkout session. details

PUT /ucp/checkout/sessions/{session_id}

Update a session. details

POST /ucp/checkout/sessions/{session_id}/payment-intent

Create a Stripe PaymentIntent for the session. details

POST /ucp/checkout/sessions/{session_id}/complete

Complete the session. Idempotent: completing the same session again returns the same order. details

POST /ucp/public/checkout/sessions

Buyer-facing session create. details

PUT /ucp/public/checkout/sessions/{session_id}

Buyer-facing session update. details

POST /ucp/public/checkout/sessions/{session_id}/payment-intent

Create a Stripe PaymentIntent for buyer confirmation. details

POST /ucp/public/checkout/sessions/{session_id}/complete

Buyer-facing session complete. details

Account, keys & readiness

GET /v1/account/auth

Verify the authenticated tenant and key context: auth mode, api_key_scopes (always an array), rate_limit_per_minute, and expiry metadata (api_key_expires_at, api_key_expires_in_days, api_key_expiry_status) when the key has expiry. guide

GET /v1/account/status

Tenant plan and key status.

GET /v1/account/usage

Monthly usage and quota projection. details

GET /v1/account/readiness

Go-live checklist: key access and TTL stability, catalog/inventory, an active checkout.completed endpoint, successful delivery without recent abandoned failures, and order flow. guide

GET /v1/account/api-keys

List API keys for the tenant.

POST /v1/account/api-keys

Create an API key.

POST /v1/account/api-keys/{api_key_id}/rotate

Rotate a key.

POST /v1/account/api-keys/{api_key_id}/revoke

Revoke a key.

POST /v1/account/checkout-access-tokens

Mint a short-lived public checkout token. details

POST /v1/account/buyer-checkout-links

Create a branded buyer checkout link scoped to one SKU and quantity, with optional merchant_reference_id (max 128 chars, [a-zA-Z0-9._:-]), success_url and cancel_url.

POST /v1/account/buyer-checkout-links/regenerate

Mint a fresh branded buyer link from a previous buyer URL or token, keeping the same scope.

Webhooks

GET /v1/webhooks/endpoints

List webhook endpoints. details

POST /v1/webhooks/endpoints

Register a webhook endpoint. details

DELETE /v1/webhooks/endpoints/{endpoint_id}

Deactivate an endpoint. Delivery history and metrics stay queryable after retirement. details

GET /v1/webhooks/deliveries

Delivery history, including attempt and next_retry_at so you can see whether a delivery is still scheduled for retry. details

GET /v1/webhooks/metrics

Tenant-scoped success rate, pending count, abandoned count and p95 delivery latency for a window (event_type, window_hours). details

Integrations — Shopify

GET /v1/integrations/shopify/status

Shopify integration status for the current tenant.

GET /v1/integrations/shopify/stores

Connected Shopify stores.

GET /v1/integrations/shopify/sync-logs

Latest Shopify-origin order sync events.

GET /v1/integrations/shopify/webhook-events

Webhook processing events. Filters: status, shop_domain.

Transaction Trace

Use an order UUID or order number to inspect the lifecycle of one agent purchase. The response combines order creation, status changes, webhook attempts, response status, and delivery duration without returning webhook payloads or response bodies.

terminal
curl -sS "https://api.ordercore.ai/v1/orders/OC-2026-0001/trace" \
  -H "X-API-Key: oc_live_xxx"
json
{
  "trace_version": "2026-07-15",
  "order_id": "6c98...",
  "order_number": "OC-2026-0001",
  "order_status": "confirmed",
  "summary": {
    "event_count": 3,
    "state_changes": 1,
    "webhook_deliveries": 1,
    "webhook_failures": 0,
    "webhook_retries": 0
  },
  "timeline": [
    {"type": "order", "label": "order.created", "status": "pending"},
    {"type": "order_event", "label": "order.confirmed", "status": "confirmed"},
    {"type": "webhook", "label": "checkout.completed", "status": "success", "attempt": 1}
  ]
}

Create Order

POST /v1/orders

json
{
  "customer_id": "cust_123",
  "items": [
    {"sku_id": "sku_123", "quantity": 2}
  ],
  "idempotency_key": "your-idempotency-key"
}
json
{
  "id": "order_...",
  "status": "pending",
  "created_at": "2026-02-09T12:34:56Z",
  "order_number": "OC-000123"
}

Public Direct Checkout Reference

Preferred direct-AI buyer flow is tokenized public checkout with Stripe PaymentIntent confirmation:

  1. POST /v1/account/checkout-access-tokens
  2. POST /ucp/public/checkout/sessions
  3. PUT /ucp/public/checkout/sessions/{session_id}
  4. POST /ucp/public/checkout/sessions/{session_id}/payment-intent
  5. Confirm client_secret in Stripe.js / Payment Element
  6. POST /ucp/public/checkout/sessions/{session_id}/complete with payment_data.payment_intent_id
Repo reference flow: scripts/public_checkout_flow.sh. It runs token issuance, public session setup, and PaymentIntent creation, then prints the final complete call to use after client-side confirmation.

Branded buyer page: /direct-ai-buyer-checkout

Browser-side operator reference: /direct-ai-reference-client

Browser config endpoint: https://api.ordercore.ai/direct-ai/browser-config

Scoped buyer link behavior: one branded buyer link creates at most one checkout session; reopening the same link resumes that session instead of minting a new one until checkout is completed. After completion, the same link returns 410 buyer_link_consumed. If you pass email, the link is locked to that buyer email. Every link also carries a signed merchant_reference_id for lead-to-order correlation.

json
{
  "sku_id": "sku_123",
  "quantity": 1,
  "currency": "USD",
  "merchant_reference_id": "lead-123",
  "email": "buyer@example.com",
  "success_url": "https://merchant.example/thank-you",
  "cancel_url": "https://merchant.example/cart",
  "full_name": "Jane Doe"
}
Unified helpers in repo: scripts/ordercore_merchant_helper.py, scripts/ordercore_merchant_helper.mjs, and scripts/ordercore_merchant_sdk.mjs. Python and Node CLIs now expose the same command-spec and machine-readable help shape. The SDK exports the same operations for direct import into merchant services.

Create flow: python3 scripts/ordercore_merchant_helper.py buyer-link-create --sku-id sku_123 --url-only

CSV row flow: python3 scripts/ordercore_merchant_helper.py buyer-link-create --catalog-csv ./catalog.csv --from-csv-row 1 --url-only

Batch flow: python3 scripts/ordercore_merchant_helper.py buyer-links-batch-from-csv --catalog-csv ./catalog.csv --start-row 1 --end-row 10 --output csv

Regenerate flow: python3 scripts/ordercore_merchant_helper.py buyer-link-regenerate --buyer-checkout-url https://ordercore.ai/direct-ai-buyer-checkout?token=... --url-only

Lookup flow: python3 scripts/ordercore_merchant_helper.py orders-lookup --merchant-reference-id lead-123 --output csv

Polling-safe lookup: python3 scripts/ordercore_merchant_helper.py orders-lookup --merchant-reference-id lead-123 --allow-missing

Auth preflight: python3 scripts/ordercore_merchant_helper.py account-auth --output json

Readiness preflight: python3 scripts/ordercore_merchant_helper.py account-readiness --output json

Go-live preflight: python3 scripts/ordercore_merchant_helper.py go-live-preflight --event-type checkout.completed --window-hours 24 --output json

Webhook ops: python3 scripts/ordercore_merchant_helper.py webhook-endpoints-list

Webhook smoke: python3 scripts/ordercore_merchant_helper.py webhook-smoke-trigger --mode retryable

Bootstrap wizard: bash scripts/ordercore_quick_setup.sh

Connector wizard: bash scripts/ordercore_connector_quick_setup.sh --platform shopify

Public path chooser: /get-started

Python JSON help: python3 scripts/ordercore_merchant_helper.py help --command webhook-metrics --format json

Node variant: node scripts/ordercore_merchant_helper.mjs webhook-metrics --event-type checkout.completed --window-hours 24 --output csv

Node readiness preflight: node scripts/ordercore_merchant_helper.mjs account-readiness --output json

Node go-live preflight: node scripts/ordercore_merchant_helper.mjs go-live-preflight --event-type checkout.completed --window-hours 24 --output json

Node JSON help: node scripts/ordercore_merchant_helper.mjs help --command webhook-metrics --format json

Merchant snippets

terminal
curl -sS -X POST https://api.ordercore.ai/v1/account/buyer-checkout-links \
  -H "X-API-Key: oc_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "sku_id": "sku_123",
    "quantity": 1,
    "currency": "USD",
    "merchant_reference_id": "lead-123",
    "email": "buyer@example.com",
    "success_url": "https://merchant.example/thank-you",
    "cancel_url": "https://merchant.example/cart"
  }'
javascript
const response = await fetch("https://api.ordercore.ai/v1/account/buyer-checkout-links", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ORDERCORE_API_KEY,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    sku_id: "sku_123",
    quantity: 1,
    currency: "USD",
    merchant_reference_id: "lead-123",
    email: "buyer@example.com",
    success_url: "https://merchant.example/thank-you",
    cancel_url: "https://merchant.example/cart"
  })
});

const data = await response.json();
console.log(data.buyer_checkout_url);
terminal
payload := strings.NewReader(`{"sku_id":"sku_123","quantity":1,"currency":"USD","merchant_reference_id":"lead-123","email":"buyer@example.com","success_url":"https://merchant.example/thank-you","cancel_url":"https://merchant.example/cart"}`)
req, _ := http.NewRequest(http.MethodPost, "https://api.ordercore.ai/v1/account/buyer-checkout-links", payload)
req.Header.Set("X-API-Key", os.Getenv("ORDERCORE_API_KEY"))
req.Header.Set("Content-Type", "application/json")

resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()

var body struct {
  BuyerCheckoutURL string `json:"buyer_checkout_url"`
}
json.NewDecoder(resp.Body).Decode(&body)
fmt.Println(body.BuyerCheckoutURL)
terminal
curl -sS -X POST https://api.ordercore.ai/v1/account/buyer-checkout-links/regenerate \
  -H "X-API-Key: oc_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "buyer_checkout_url": "https://ordercore.ai/direct-ai-buyer-checkout?token=...",
    "ttl_minutes": 15
  }'
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py buyer-link-regenerate \
  --buyer-checkout-url "https://ordercore.ai/direct-ai-buyer-checkout?token=..." \
  --url-only
json
{
  "payment_data": {
    "handler_id": "card",
    "payment_intent_id": "pi_12345"
  }
}
terminal
curl -sS "https://api.ordercore.ai/v1/orders/lookup?merchant_reference_id=lead-123" \
  -H "X-API-Key: oc_live_xxx"
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py orders-lookup \
  --merchant-reference-id lead-123 \
  --output csv
terminal
python3 scripts/ordercore_merchant_helper.py help --format json
terminal
python3 scripts/ordercore_merchant_helper.py help \
  --command webhook-metrics \
  --format json
terminal
ORDERCORE_API_KEY=oc_live_xxx \
node scripts/ordercore_merchant_helper.mjs orders-lookup \
  --merchant-reference-id lead-123 \
  --allow-missing \
  --output jsonl
terminal
node scripts/ordercore_merchant_helper.mjs help --format json
terminal
node scripts/ordercore_merchant_helper.mjs help \
  --command webhook-metrics \
  --format json
javascript
import { ordersLookup, webhookMetrics, resolveApiKey } from "./scripts/ordercore_merchant_sdk.mjs";

const apiKey = resolveApiKey({ env: process.env });
const lookup = await ordersLookup({
  apiKey,
  merchantReferenceId: "lead-123",
  allowMissing: true,
});
const metrics = await webhookMetrics({
  apiKey,
  eventType: "checkout.completed",
  windowHours: 24,
});

console.log({ lookup, metrics });

Use --allow-missing when your merchant workflow polls before checkout or order creation exists yet. In that mode the helper prints {"status":"not_found"} and exits successfully.

Webhook Endpoint Ops

terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-endpoints-list
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-endpoints-create \
  --url https://example.com/webhooks/ordercore \
  --events checkout.completed
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-endpoints-delete \
  --endpoint-id 123e4567-e89b-12d3-a456-426614174000

Delete is a deactivation operation. Delivery history stays queryable after endpoint retirement.

terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-deliveries-list \
  --event-type checkout.completed \
  --limit 10
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-deliveries-list \
  --event-type checkout.completed \
  --limit 10 \
  --output jsonl
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-metrics \
  --event-type checkout.completed \
  --window-hours 24
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-metrics \
  --event-type checkout.completed \
  --window-hours 24 \
  --output csv
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-smoke-trigger \
  --mode standard
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-smoke-trigger \
  --mode retryable

Catalog CSV Import

Use POST /v1/onboarding/catalog-csv when you want a self-serve starting catalog without Shopify, WooCommerce, or another platform connector.

Required CSV headers:

  • product_name
  • sku_code

Optional headers:

  • product_description
  • product_external_id or product_ref
  • sku_name
  • unit_price or price
  • quantity_on_hand or stock_qty
terminal
curl -sS -X POST https://api.ordercore.ai/v1/onboarding/catalog-csv \
  -H "X-API-Key: oc_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "USD",
    "price_list_code": "IMPORT",
    "location_code": "IMPORT-WH",
    "location_name": "Import Warehouse",
    "csv": "product_name,sku_code,unit_price,quantity_on_hand\nStarter Pack,STARTER-1,49.00,10"
  }'
json
{
  "status": "ok",
  "currency": "USD",
  "price_list_code": "IMPORT",
  "location_code": "IMPORT-WH",
  "imported_rows": 1,
  "sample_order_item": {
    "sku_id": "sku_...",
    "quantity": 1
  },
  "created_or_updated": {
    "products": 1,
    "skus": 1,
    "prices": 1,
    "inventory_rows": 1,
    "price_lists": 1,
    "locations": 1
  }
}
The import is idempotent on product/SKU codes. Re-running the same CSV updates the starter catalog instead of creating duplicate rows.
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py catalog-csv-import \
  --csv-file ./catalog.csv \
  --price-list-code IMPORT \
  --location-code IMPORT-WH
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py buyer-link-create \
  --catalog-csv ./catalog.csv \
  --from-csv-row 1 \
  --url-only
terminal
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py buyer-links-batch-from-csv \
  --catalog-csv ./catalog.csv \
  --start-row 1 \
  --end-row 10 \
  --merchant-reference-prefix launch-20260316 \
  --output csv

Order actions

POST /v1/orders/{order_id}/confirm – confirm order

POST /v1/orders/{order_id}/cancel – cancel order

json
{
  "reason": "customer request",
  "metadata": {"source": "support"}
}

Webhooks (Outbound)

Manage tenant webhook endpoints:

  • GET /v1/webhooks/endpoints
  • POST /v1/webhooks/endpoints
  • DELETE /v1/webhooks/endpoints/{endpoint_id}
  • GET /v1/webhooks/deliveries
  • GET /v1/webhooks/metrics
json
{
  "url": "https://example.com/webhooks/ordercore",
  "events": ["checkout.completed"]
}
The create response returns a secret once. Store it securely. Supported direct-AI event today: checkout.completed (event names are normalized to lowercase).

DELETE /v1/webhooks/endpoints/{endpoint_id} now deactivates the endpoint instead of erasing it. Delivery history and metrics stay available for ops and support after an endpoint is retired.

Every delivery includes these headers:

  • X-OrderCore-Event – event name such as checkout.completed
  • X-OrderCore-Delivery-ID – unique delivery identifier
  • X-OrderCore-Signaturesha256= + hex HMAC of the raw request body using your endpoint secret

Production delivery is no longer single-shot. Retryable failures stay pending and are retried automatically with capped backoff. Non-retryable 4xx failures move to failed; exhausted retries move to abandoned.

GET /v1/webhooks/deliveries now returns attempt and next_retry_at so support can see whether a delivery is still scheduled for retry.

GET /v1/webhooks/metrics?event_type=checkout.completed&window_hours=24 returns tenant-scoped success rate, pending count, abandoned count, and p95 delivery latency for the selected window.

Verify the signature against the raw, unparsed request body before accepting the event.

javascript
// Node.js
import crypto from "node:crypto";

function verifyOrderCoreSignature(rawBody, signatureHeader, endpointSecret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", endpointSecret)
    .update(rawBody)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader || "", "utf8"),
  );
}
terminal
// Go
func verifyOrderCoreSignature(rawBody []byte, signatureHeader, endpointSecret string) bool {
    mac := hmac.New(sha256.New, []byte(endpointSecret))
    mac.Write(rawBody)
    expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signatureHeader))
}

Production smoke coverage now includes a synthetic checkout.completed delivery via ./scripts/smoke_checkout_completed_webhook.sh and a fail-first retry verification via ./scripts/smoke_checkout_completed_retry_worker.sh.

UCP (Experimental)

Discovery: GET /ucp/.well-known/ucp

Checkout sessions:

  • POST /ucp/checkout/sessions
  • PUT /ucp/checkout/sessions/{session_id}
  • POST /ucp/checkout/sessions/{session_id}/complete

Errors

json
{"error":"unauthorized","message":"Missing API key"}
{"error":"unauthorized","message":"API key expired","auth_reason":"expired_api_key"}
{"error":"rate_limited","message":"Too many requests"}
{"error":"not_implemented","message":"This endpoint is not yet implemented"}

Limits

Three different limits apply. They are not three versions of the same number, and they are measured over different windows on different surfaces. Read the live values from the API rather than hardcoding them.

  • Rate limit — 1000 requests per minute, per API key. Best-effort, enforced per key. GET /v1/account/auth returns rate_limit_per_minute for the calling key; read it at startup instead of hardcoding.
  • Monthly quota — 50,000 API calls per month on the paid plan. Responses carry usage headers, and GET /v1/account/usage returns consumption plus a projection for the current period.
  • Direct-AI evaluation allowance — 10 calls per day. A public allowance on the Direct-AI assistant surface (/ai-integrations) for evaluation, demos and routing checks before billing. It is separate from the two limits above and does not draw on the monthly quota.