Skip to main content

DEVELOPER DOCUMENTATION · V1

Connect your field-service workflows.

Read workspace records, create customers and jobs, and update them with safe retries.

Authentication

Create a key in Settings → API keys. Select only the needed permissions. A key belongs to one workspace and expires after 30, 90, or 365 days. Revocation and loss of the issuer's manager role prevent subsequent requests.

Send the key in the Authorization header. Keep keys on your server or in a secret manager. Cookie sessions do not authenticate this API, and browser CORS access is not enabled.

Authorization: Bearer <your-api-key>
Accept: application/json

Base URL: your SnapJobAI origin followed by /api/v1. The examples use an origin you configure in your integration.

Endpoints and permissions

ResourceMethodsScopes
/api/v1/customersGET collection, GET record, POST, PATCHcustomers:read / customers:write
/api/v1/jobsGET collection, GET record, POST, PATCHjobs:read / jobs:write
/api/v1/invoicesGET collection, GET recordinvoices:read
/api/v1/equipmentGET collection, GET recordequipment:read
/api/v1/techniciansGET collection, GET recordtechnicians:read

Append /{id} to fetch or PATCH one record. Write scope does not imply read scope. Invoice reads include charges, credits, net payments, and remaining balance; invoice lists contain summary fields. Equipment details include service history. No DELETE or financial write endpoint is exposed.

Pagination and response shape

Lists return { "data": [...], "nextCursor": "uuid-or-null" }. Use ?limit=50 (1–100), then pass the returned cursor as ?after=.... Records are ordered by ID. Pagination is not a snapshot: new records may appear before your cursor, so periodic full reconciliation is appropriate.

Single-record and write responses return { "data": { ... } }. Times use ISO 8601; monetary amounts use integer USD cents; tax rates use basis points. An invoice's amountPaidCents is net of recorded refunds and dispute fund movements, floored at zero.

Invoice detail includes paymentLinkMethod (card, ach, or null), paymentProcessing, collectionHold,refundHold, disputedCents, and collectionShortfallCents. Fetch detail before acting on a list summary. A positive balance alone does not establish that collection is appropriate; holds require office review. The API provides no financial write actions.

Create a customer or job

Every POST and PATCH requires a unique UUID Idempotency-Key. Retry an interrupted request with the same key, path, method, body, and If-Match header. A successful retry returns the original response with Idempotency-Replayed: true. Reusing the key with different details returns 409. Receipts are retained for the life of the integration key; rotate keys before changing an integration's ownership.

POST /api/v1/customers
Content-Type: application/json
Idempotency-Key: <new-uuid>

{ "name": "Oak Street Owner", "email": "owner@example.com" }

Customer fields: name (required for POST), email, phone, addressLine1, city, state, zip, notes.

POST /api/v1/jobs
Content-Type: application/json
Idempotency-Key: <new-uuid>

{
  "customerId": "<customer-uuid>",
  "title": "Annual furnace service",
  "status": "scheduled",
  "scheduledStart": "2026-10-01T09:00:00-04:00",
  "scheduledEnd": "2026-10-01T10:00:00-04:00"
}

Job fields: customerId and title (required for POST), technicianId, description, status, priority, scheduledStart, scheduledEnd, and address fields. Customer and technician IDs must belong to the key's workspace; technicians must be active.

Status values: unscheduled, scheduled, in_progress, completed, cancelled. Priority values: low, normal, high, emergency. Timestamps require seconds and a timezone offset. Use null to clear optional fields; clear both schedule fields together when removing an appointment. Unknown fields are rejected.

A start time without an end reserves 60 minutes. Assigned visits cannot overlap another active visit for the same technician; adjacent visits are allowed. A conflicting assignment, reschedule, or reopening returns 409 with code schedule_conflict. Completed and cancelled jobs release their reserved time.

Update without overwriting newer work

Fetch the record and keep its ETag header. Send it unchanged as If-Match when PATCHing. Omitted fields are retained. A missing precondition returns 428; a stale one returns 412. Fetch the latest record and decide how to apply your change before sending a new request with a new Idempotency-Key.

PATCH /api/v1/jobs/<job-uuid>
Content-Type: application/json
Idempotency-Key: <new-uuid>
If-Match: "<etag-from-GET>"

{ "status": "completed" }

Jobs with invoices or equipment service history cannot move to another customer. The existing service and financial history checks still apply.

Limits and errors

Each workspace shares a limit of 120 authenticated API requests per minute across its keys. JSON bodies are limited to 64 KiB. Writes require an active subscription or trial when billing is enabled; read access remains available.

Errors return { "error": { "code": "...", "message": "...", "requestId": "..." } }. Keep the X-Request-Id response header for support. Never send your key in a support message.

  • 400: invalid fields, JSON, pagination, or missing idempotency key.
  • 401 / 403: invalid key or missing permission.
  • 402: subscription needs attention. 404: record unavailable in this workspace.
  • 409: idempotency or schedule conflict. 412 / 428: update precondition failed or missing.
  • 413 / 415: request body too large or unsupported content type.
  • 429: wait for Retry-After, then retry. 500: retry with the same Idempotency-Key.

V1 does not send outbound webhooks. Poll and reconcile records as needed. Additive response fields may be introduced; clients should ignore fields they do not recognize.