OrderCore
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. 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>
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. Get API key: GET /health
  2. Create your first order: POST /v1/onboarding/demo-data
  3. Confirm order → trigger webhook: POST /v1/orders

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.
export API_KEY="oc_live_..."

# 1) Get API key + health preflight
curl -sS https://api.ordercore.ai/health

# 2) Create your first order
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) Confirm order → trigger webhook
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 first retry-safe order and verify webhook delivery
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}]}"
Requires jq for onboarding response parsing.

Endpoints

GET /health – status

GET /direct-ai/manifest – public direct AI checkout manifest (commercial + technical entry points)

GET /direct-ai/browser-config – public browser-safe checkout config (Stripe publishable key when configured)

/ai-integrations – public AI integrations hub with OpenAI, Claude, Gemini, DeepSeek, and Grok packs plus free-tier and billing model summary

GET /integrations/catalog – public add-ons catalog (connectors, UCP compatibility summary)

GET /integrations/shopify/status – public Shopify install diagnostics (non-sensitive)

POST /v1/account/checkout-access-tokens – mint short-lived public checkout token

POST /v1/account/buyer-checkout-links – create branded buyer checkout link scoped to one SKU + quantity, with optional merchant_reference_id, success_url, and cancel_url (merchant_reference_id: max 128 chars, allowed [a-zA-Z0-9._:-])

POST /v1/account/buyer-checkout-links/regenerate – mint a fresh branded buyer link from a previous buyer URL or token while keeping the same scope

POST /ucp/public/checkout/sessions/{session_id}/payment-intent – create Stripe PaymentIntent for buyer confirmation

GET /v1/products – list products (filters: status)

POST /v1/products – create product

GET /v1/products/{product_id} – product detail

PATCH /v1/products/{product_id} – update product

DELETE /v1/products/{product_id} – delete 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)

GET /v1/orders – list orders

GET /v1/orders/lookup?merchant_reference_id=... – lookup latest checkout session and order by merchant reference

GET /v1/orders/{order_id} – order detail

GET /v1/orders/{order_id}/trace – tenant-safe order, status event, and webhook delivery timeline

GET /v1/account/auth – verify authenticated tenant and key context (auth mode, scopes, rate limit). Response includes api_key_scopes (always an array), rate_limit_per_minute, and key expiry metadata (api_key_expires_at, api_key_expires_in_days, api_key_expiry_status) when the key has expiry.

GET /v1/account/status – tenant plan and key status

GET /v1/account/usage – monthly usage and quota projection

GET /v1/account/readiness – go-live checklist for key access + TTL stability, catalog/inventory, active checkout.completed endpoint, successful delivery without recent abandoned webhook failures, and order flow

POST /v1/onboarding/catalog-csv – import a starter catalog, prices, and inventory without Shopify or another connector

GET /v1/integrations/shopify/status – Shopify integration status for 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.

curl -sS "https://api.ordercore.ai/v1/orders/OC-2026-0001/trace" \
  -H "X-API-Key: oc_live_xxx"
{
  "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

{
  "customer_id": "cust_123",
  "items": [
    {"sku_id": "sku_123", "quantity": 2}
  ],
  "idempotency_key": "your-idempotency-key"
}
{
  "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.

{
  "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

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"
  }'
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);
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)
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
  }'
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
{
  "payment_data": {
    "handler_id": "card",
    "payment_intent_id": "pi_12345"
  }
}
curl -sS "https://api.ordercore.ai/v1/orders/lookup?merchant_reference_id=lead-123" \
  -H "X-API-Key: oc_live_xxx"
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py orders-lookup \
  --merchant-reference-id lead-123 \
  --output csv
python3 scripts/ordercore_merchant_helper.py help --format json
python3 scripts/ordercore_merchant_helper.py help \
  --command webhook-metrics \
  --format json
ORDERCORE_API_KEY=oc_live_xxx \
node scripts/ordercore_merchant_helper.mjs orders-lookup \
  --merchant-reference-id lead-123 \
  --allow-missing \
  --output jsonl
node scripts/ordercore_merchant_helper.mjs help --format json
node scripts/ordercore_merchant_helper.mjs help \
  --command webhook-metrics \
  --format json
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

ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-endpoints-list
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-endpoints-create \
  --url https://example.com/webhooks/ordercore \
  --events checkout.completed
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.

ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-deliveries-list \
  --event-type checkout.completed \
  --limit 10
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-deliveries-list \
  --event-type checkout.completed \
  --limit 10 \
  --output jsonl
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-metrics \
  --event-type checkout.completed \
  --window-hours 24
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-metrics \
  --event-type checkout.completed \
  --window-hours 24 \
  --output csv
ORDERCORE_API_KEY=oc_live_xxx \
python3 scripts/ordercore_merchant_helper.py webhook-smoke-trigger \
  --mode standard
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
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"
  }'
{
  "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.
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
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
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

{
  "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
{
  "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.

// 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"),
  );
}
// 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

{"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"}

Rate limits

Default: 1000 requests/minute per API key (best-effort).