OrderCore Back to Home

OrderCore API Guide

Public API usage only. Internal business logic is intentionally omitted.

Plugin packages: /downloads.html

Base URLs

Authentication

Send your API key on every request:

curl -H "X-API-Key: oc_live_..." https://api.ordercore.ai/health

Idempotency

For create operations include:

Pagination

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

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)

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

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/status – tenant plan and key status

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

GET /v1/account/readiness – go-live checklist for catalog, inventory, webhooks, 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"
}
Merchant helpers in repo: scripts/create_buyer_checkout_link.sh and scripts/regenerate_buyer_checkout_link.sh. Set API_KEY, SKU_ID, and optionally MERCHANT_REFERENCE_ID, BUYER_EMAIL, SUCCESS_URL, CANCEL_URL.

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

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.

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.

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