Built by a Sparky for Sparkies. Join the waitlist

Developers

Connect your other tools

Send new jobs, accepted quotes and paid invoices to Zapier, n8n or Make, and let ChatGPT or Claude look up your jobs. On Sparky Plus and above.

1. Make an API key

In the app, go to Settings, Connections (the business owner only). Give the key a name, tick only what it needs to do, and tap Make a key. Copy the key straight away: it starts with sb_live_ and you only see it once. We keep a fingerprint of it, not the key itself.

Each key does only what you ticked:

  • read:jobs: See jobs
  • write:jobs: Add jobs
  • read:clients: See clients
  • write:clients: Add clients
  • read:quotes: See quotes and their totals
  • read:invoices: See invoices and amounts
  • write:notes: Add notes to jobs
  • read:schedule: See the schedule (visits)

Money (quote totals, invoice amounts) only ever comes back with read:quotes or read:invoices. A key can never change your settings, staff or billing. Revoke a key in the same place and it stops working at once. Keys also stop working if the owner who made them is no longer an owner of the business.

2. The REST API

Every request sends the key as a bearer token. Answers are JSON. Money is in whole cents (12350 is $123.50, GST included), dates are YYYY-MM-DD and times are ISO 8601 in UTC.

curl https://sparkybuddy.com.au/api/v1/jobs?status=booked \
  -H "Authorization: Bearer sb_live_your_key"

Lists come back a page at a time, newest first. Pass the next_cursor you got back to get the next page (it's null on the last):

{
  "data": [ { "id": "…", "number": 1042, "title": "Replace switchboard", "status": "booked", … } ],
  "next_cursor": "WzEwNDJd"
}

curl "https://sparkybuddy.com.au/api/v1/jobs?limit=50&cursor=WzEwNDJd" -H "Authorization: Bearer sb_live_your_key"
RequestNeedsWhat it does
GET /clientsread:clientsYour clients, newest first. ?q= searches name, business, email and phone.
POST /clientswrite:clientsAdd a client: name, and any of kind, business_name, email, phone, billing_address, notes.
GET /jobsread:jobsJobs, newest first. ?status=, ?client_id= and ?q= to narrow it.
POST /jobswrite:jobsAdd a job for client_id, or with a new client (also needs write:clients). Optional first visit.
GET /jobs/{id}read:jobsOne job. Its quotes come too with read:quotes, its invoices with read:invoices.
POST /jobs/{id}/noteswrite:notesAdd a dated note to the end of the job's notes. Never replaces what's there.
GET /quotesread:quotesQuotes with totals. ?status= (draft, sent, accepted, declined) and ?job_id=.
GET /invoicesread:invoicesInvoices with amounts paid and owing. ?status= (draft, sent, paid, void) and ?job_id=.
GET /schedule?from=&to=read:scheduleVisits between two dates (YYYY-MM-DD, up to 62 days), in order.

Add a job with a new client and a first visit:

curl -X POST https://sparkybuddy.com.au/api/v1/jobs \
  -H "Authorization: Bearer sb_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Install two power points",
    "site_address": "12 Example St, Southport QLD 4215",
    "client": { "name": "Alex Sample", "phone": "0491 570 006" },
    "scheduled_for": "2026-11-03",
    "start_time": "08:00",
    "duration_minutes": 120
  }'

Add a note to a job:

curl -X POST https://sparkybuddy.com.au/api/v1/jobs/JOB_ID/notes \
  -H "Authorization: Bearer sb_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Customer rang: side gate code is 1234" }'

3. Webhooks

Instead of asking us over and over, let us tell you. In Settings, Connections, add the https address your tool gave you (in Zapier, a "Catch Hook"; in n8n or Make, a Webhook trigger) and tick the events you want:

  • job.created: A job is created
  • job.status_changed: A job moves to a new status
  • quote.accepted: A customer accepts a quote
  • invoice.paid: An invoice is paid in full
  • enquiry.received: A new enquiry comes in
  • visit.booked: A visit is booked on the schedule

Each one is a POST with a JSON body like this. "Send a test event" sends a ping, so your tool has a sample to map.

{
  "id": "6f1c…",
  "type": "invoice.paid",
  "created_at": "2026-10-26T03:12:45.000Z",
  "data": {
    "invoice": { "id": "…", "number": 207, "job_id": "…", "total_cents": 48400, "paid_on": "2026-10-26", "payment_method": "card" }
  }
}

Checking it came from us. Each webhook is signed the Standard Webhooks way, with the signing secret shown when you added it (it starts whsec_). Three headers come with it: webhook-id, webhook-timestamp and webhook-signature. The signature is v1, then the base64 HMAC-SHA256 of id.timestamp.body, keyed with the secret's bytes (the part after whsec_, base64-decoded). Reject it if the timestamp is more than 5 minutes old.

// Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

function fromUs(secret, headers, rawBody) {
  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const signed = `${headers["webhook-id"]}.${headers["webhook-timestamp"]}.${rawBody}`;
  const expected = "v1," + createHmac("sha256", key).update(signed).digest("base64");
  const fresh = Math.abs(Date.now() / 1000 - Number(headers["webhook-timestamp"])) < 300;
  return fresh && headers["webhook-signature"].split(" ").some(
    (s) => s.length === expected.length && timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}

Answer with any 2xx status within 10 seconds. If you don't, we try again later (after 1 minute, 5 minutes, 30 minutes, then hours apart), 8 tries in all over about two days, with the same webhook-id so you can ignore repeats. We don't follow redirects. After 15 failures in a row the webhook is switched off and the owner is told; switch it back on in Settings. The last 20 deliveries for each webhook are listed there.

4. ChatGPT, Claude and other AI assistants

SparkyBuddy has an MCP server, the standard way AI assistants connect to apps. Point your assistant at this address and give it an API key as the bearer token:

https://sparkybuddy.com.au/api/mcp

It offers these tools, each only if the key has the matching box ticked:

  • find_jobs and get_job (read:jobs)
  • find_clients (read:clients)
  • list_schedule (read:schedule)
  • add_job_note (write:notes)
  • create_job (write:jobs, and write:clients for a new client)

It works with assistants and tools that let you set a bearer token on an MCP connection: Claude Code, the Claude and OpenAI APIs' MCP connectors, n8n's MCP client and others. For example, in Claude Code:

claude mcp add --transport http jobs https://sparkybuddy.com.au/api/mcp \
  --header "Authorization: Bearer sb_live_your_key"

Make a separate key for each assistant, and only tick the write boxes if you want it to change things. Assistants can get things wrong: check what it adds.

5. Errors and limits

Errors come back as JSON with a code and a message written for people:

{ "error": { "code": "missing_scope", "message": "This key can't do that. It needs: read:invoices. …", "needed": ["read:invoices"] } }
  • 400 something in the request isn't right (the message says what)
  • 401 no key, a wrong key or a revoked one
  • 403 the key doesn't have that box ticked, or the plan doesn't include connections
  • 404 no such record in your business (or no such endpoint)
  • 429 too many requests: wait for the number of seconds in the Retry-After header

Each key can make 120 requests a minute, and 60 changes every 10 minutes. Pages are up to 100 records (50 if you don't say). A key only ever sees its own business's records.