OrderCore Back to Home
API-first docs for developers

OrderCore API Guide

OrderCore is the API that lets AI agents complete purchases. Built for developers shipping AI apps with a clear first-order path and a 3-day trial outcome you can show to product and revenue teams.

What you should leave trial with: one validated idempotent order flow, readiness evidence, and a clear GO/NO-GO decision. Public API usage only. Internal business logic is intentionally omitted. Plugin packages: /downloads.html.

What OrderCore is, who it serves, and what it simplifies

Use OrderCore when you need checkout + order reliability as an API layer for AI assistants or custom apps, without rebuilding idempotency and webhook operations.

Who It's For
  • Developers shipping AI checkout into product UX.
  • SaaS apps that need reliable order creation fast.
  • Teams adding Shopify/WooCommerce only when needed.
What It Replaces
  • Hand-built duplicate order handling.
  • One-off webhook retry infrastructure.
  • Fragmented onboarding scripts and setup drift.
What Gets Easier
  • First success to production transition.
  • Operational checks for auth, quota, and delivery.
  • Direct API flow with optional connector expansion.
Not Ideal For
  • Teams looking for a no-code storefront instead of API checkout.
  • Projects with no developer time for initial setup and testing.
  • Teams that cannot name one owner for checkout + webhook ops.
Get API key Use your live oc_live_... key and confirm API access with GET /health.
Create your first order Run POST /v1/onboarding/demo-data and resolve sample IDs.
Confirm order → trigger webhook Call POST /v1/orders with an idempotency key and verify webhook delivery.
Trust before scale

Operational Proof Surface

Day 13 evidence checkpoint: show the security, reliability, and commercial trust layer before increasing campaign spend.

Security Controls
  • Scoped API auth model and explicit endpoint boundaries.
  • Signed webhook delivery path with retry visibility.
  • Policy references: Terms and Privacy.
Reliability Evidence
  • Live runtime checks in System Dashboard.
  • Readiness + billing preflight commands available in docs and console.
  • Release/smoke gates block degraded rollout states.
Commercial Trust
  • Stripe-managed billing with explicit cancellation flow.
  • Guided support path via /support.html.
  • Clear go-live criteria before scaling paid traffic.

Base URLs

Authentication

Send your API key on every request:

curl -H "X-API-Key: oc_live_..." https://api.ordercore.ai/v1/account/auth

Idempotency

For create operations include:

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:

Built for real systems:

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

Works locally without payment. Add billing when you're ready to go live.
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/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)

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:

Optional headers:

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:

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

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:

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).

Helpful links