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 live site, 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/orders
201 Created
curl https://api.sparx.works/v1/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/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/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.placed event on the internal bus. To receive events in your own app, register a webhook and verify each signed delivery. Subscribable events span orders, content, media, redirects, and email delivery: the full catalog 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?