Quickstart.

API v1

Go from zero to a live integration in about ten minutes. You'll create an API key, place an order over the REST API, read the response, and see how to react to events — the same surface the dashboard uses, because every Sparx feature is an API endpoint first.

Updated 2026-06-0510 min read
PrerequisitesYou need a Sparx tenant with the CRM module active, and an existing customer to attach the order to. No tenant yet? Create one free — live in under five minutes, no card required.

Overview

Sparx is API-first: the dashboard, the storefront, and AI agents over MCP are all consumers of the same REST and GraphQL surface. An integration touches three things — an authenticated client (your API key), a resource you read or write, and the events Sparx emits in response.

Your appapi.sparx.works/v1Pub/Sub event
A write returns immediately and emits an event; side effects run in workers, never inline in the request.

Build the integration

Four steps, each independently runnable against your tenant.

1

Create an API key

In your dashboard, open Settings → AI integrations and create a key. The secret (sk_live_…) is shown once — store it as SPARX_KEY. Full details in Authentication.

Keys inherit Row-Level Security — a key can never read another tenant’s data, even on a malformed request. Keep it server-side and treat it like a password.
2

Place your first order

Orders live in the CRM, which owns the customer and order spine. POST a customer id and one or more line items; Sparx computes the totals. Here it is in three languages — no SDK required, just HTTP:

POST/v1/crm/orders
201 Created
curl https://api.sparx.works/v1/crm/orders \
  -H "Authorization: Bearer $SPARX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "8a1f0b2c-9d3e-4a5b-8c6d-1e2f3a4b5c6d",
    "currency": "USD",
    "items": [
      { "sku": "INJ-6.7-CR", "name": "6.7L Common-Rail Injector", "quantity": 8, "unitPrice": 289.50 }
    ]
  }'
const res = await fetch("https://api.sparx.works/v1/crm/orders", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SPARX_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    customerId: "8a1f0b2c-9d3e-4a5b-8c6d-1e2f3a4b5c6d",
    currency: "USD",
    items: [
      { sku: "INJ-6.7-CR", name: "6.7L Common-Rail Injector", quantity: 8, unitPrice: 289.5 },
    ],
  }),
});
const { data: order } = await res.json();
import os, requests

res = requests.post(
  "https://api.sparx.works/v1/crm/orders",
  headers={"Authorization": f"Bearer {os.environ['SPARX_KEY']}"},
  json={
    "customerId": "8a1f0b2c-9d3e-4a5b-8c6d-1e2f3a4b5c6d",
    "currency": "USD",
    "items": [
      {"sku": "INJ-6.7-CR", "name": "6.7L Common-Rail Injector", "quantity": 8, "unitPrice": 289.50}
    ],
  },
)
order = res.json()["data"]
3

Read the response

Every response shares one envelope: { success: true, data }. A created order comes back with a server-assigned id, an orderNumber, computed totals, and its lifecycle status:

201
{
  "success": true,
  "data": {
    "id": "0c7b1a2d-4e5f-4a6b-9c8d-2e1f0a9b8c7d",
    "orderNumber": "1042",
    "status": "placed",
    "paymentStatus": "unpaid",
    "customerId": "8a1f0b2c-9d3e-4a5b-8c6d-1e2f3a4b5c6d",
    "currency": "USD",
    "subtotal": 2316.00,
    "total": 2316.00,
    "items": [
      { "sku": "INJ-6.7-CR", "name": "6.7L Common-Rail Injector", "quantity": 8, "unitPrice": 289.50 }
    ],
    "createdAt": "2026-06-05T17:41:09Z"
  }
}
FieldTypeDescription
idstringThe order’s unique id (UUID).
orderNumberstringHuman-facing sequence number, auto-generated.
statusenumplaced · fulfilled · delivered · cancelled · refunded
paymentStatusenumunpaid · partially_paid · paid · refunded
totalnumberComputed from the line items, in currency units (e.g. 2316.00).
createdAtstringISO-8601 timestamp, always UTC.
4

React to events

Creating that order emitted an order.created event on the internal bus. To receive events in your own app, register a webhook and verify each signed delivery. Today the subscribable events are content, media, and redirect events — the full model is in Webhooks & events:

// Receive webhook deliveries — see the Webhooks guide for the full setup.
import { verifySparxWebhook } from "./verify";

export async function POST(req: Request) {
  const raw = await req.text();                       // the RAW body, for signing
  const sig = req.headers.get("x-sparx-signature") ?? "";
  if (!verifySparxWebhook(raw, sig, process.env.SPARX_WEBHOOK_SECRET)) {
    return new Response("bad signature", { status: 400 });
  }
  const event = JSON.parse(raw);                      // { id, type, tenant_id, data, … }
  if (event.type === "content.entry.published") {
    await reindex(event.data);                        // your code
  }
  return new Response("ok");                           // 2xx acknowledges delivery
}
The same event stream powers AI.An MCP agent reads and writes live data directly — no exports, no CSVs. Webhooks are for notifying external systems; MCP is for agents.

Conventions

A couple of patterns that apply across every endpoint — worth knowing before you go further.

The response envelope

Success is { "success": true, "data": … }. List endpoints add a meta object with pagination (total, per_page, next_cursor). Failures are { "success": false, "error": { "code", "message" } } with a machine-readable error.code.

Pagination

List endpoints accept take (page size, default 50) and skip (offset), and return meta.total and meta.next_cursor so you can page through large result sets.

Modules must be active

An endpoint whose module isn’t enabled for your tenant returns 403 module_disabled rather than partial behavior. Placing an order requires the crm module; see Core concepts.

Errors & status codes

Sparx uses conventional HTTP status codes and returns a machine-readable error.code on every failure. Handle these at minimum:

StatusCodeWhen
201okThe order was created.
401unauthorizedMissing, malformed, revoked, or expired API key.
403module_disabledThe key’s tenant hasn’t activated that module.
429rate_limitedToo many requests — back off and retry.

“AI builds it, Sparx keeps it.” Every endpoint you call today is versioned and deprecation-warned — never silently broken under you.

— Sparx API design principle

Frequently asked

Do I need the dashboard to use the API?

No. The dashboard is one consumer of the API — you can run an entire tenant headless. The only thing that requires the dashboard is creating your first API key.

Is GraphQL or REST recommended?

Both are first-class and derived from one schema. Use REST for simple writes and webhooks; reach for GraphQL when you need to fetch a deep object graph in one round trip.

Next steps

Was this page helpful?