- Developers shipping AI checkout into product UX.
- SaaS apps that need reliable order creation fast.
- Teams adding Shopify/WooCommerce only when needed.
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.
Use OrderCore when you need checkout + order reliability as an API layer for AI assistants or custom apps, without rebuilding idempotency and webhook operations.
oc_live_... key and confirm API access with GET /health.
POST /v1/onboarding/demo-data and resolve sample IDs.
POST /v1/orders with an idempotency key and verify webhook delivery.
Day 13 evidence checkpoint: show the security, reliability, and commercial trust layer before increasing campaign spend.
https://api.ordercore.aihttps://demo-api.ordercore.aiSend your API key on every request:
X-API-Key: <your_key>Authorization: Bearer <your_key>curl -H "X-API-Key: oc_live_..." https://api.ordercore.ai/v1/account/auth
For create operations include:
Idempotency-Keyidempotency_keyList endpoints accept page and per_page (default 20, max 100).
Use this same flow everywhere (docs, tutorial, and get-started):
GET /healthPOST /v1/onboarding/demo-dataPOST /v1/ordersAfter this flow you will have:
Built for real systems:
No store, no UI, no checkout flow needed. Just API.
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}]}"
jq for onboarding response parsing.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)
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"
}
Preferred direct-AI buyer flow is tokenized public checkout with Stripe PaymentIntent confirmation:
POST /v1/account/checkout-access-tokensPOST /ucp/public/checkout/sessionsPUT /ucp/public/checkout/sessions/{session_id}POST /ucp/public/checkout/sessions/{session_id}/payment-intentclient_secret in Stripe.js / Payment ElementPOST /ucp/public/checkout/sessions/{session_id}/complete with payment_data.payment_intent_idscripts/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"
}
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
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.
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
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_namesku_codeOptional headers:
product_descriptionproduct_external_id or product_refsku_nameunit_price or pricequantity_on_hand or stock_qtycurl -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
}
}
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
POST /v1/orders/{order_id}/confirm – confirm order
POST /v1/orders/{order_id}/cancel – cancel order
{
"reason": "customer request",
"metadata": {"source": "support"}
}
Manage tenant webhook endpoints:
GET /v1/webhooks/endpointsPOST /v1/webhooks/endpointsDELETE /v1/webhooks/endpoints/{endpoint_id}GET /v1/webhooks/deliveriesGET /v1/webhooks/metrics{
"url": "https://example.com/webhooks/ordercore",
"events": ["checkout.completed"]
}
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.completedX-OrderCore-Delivery-ID – unique delivery identifierX-OrderCore-Signature – sha256= + hex HMAC of the raw request body using your endpoint secretProduction 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.
Discovery: GET /ucp/.well-known/ucp
Checkout sessions:
POST /ucp/checkout/sessionsPUT /ucp/checkout/sessions/{session_id}POST /ucp/checkout/sessions/{session_id}/complete{"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"}
Default: 1000 requests/minute per API key (best-effort).