/api/partner/v1 · version 2026-08-26Installer API v1
For installation companies working jobs for companies on the platform. Pull a change feed of jobs, post status events, set schedules and assign technicians. Every write is idempotent and version-checked.
The job resource
Every response returns the installer-safe projection of a job: what a crew needs and nothing the company keeps to itself.
{
"id": "job_…", "version": 7, "workOrderNo": "WO-1042", "status": "ON_SITE",
"customer": { "name": "Pat Example", "phone": "801-555-0100",
"serviceAddress": { "line1": "123 Ridge Ave", "city": "Salt Lake City", "state": "UT", "postalCode": "84101" } },
"scope": { "packageName": "Heat pump 3-ton", "systemType": "HEAT_PUMP",
"equipment": { "condenser": { "make": "Example", "model": "HP-36", "tonnage": 3 } },
"accessories": ["Smart thermostat"], "supplierSources": [] },
"schedule": { "status": "CONFIRMED", "version": 2,
"startsAt": "2026-09-18T14:00:00.000Z", "endsAt": "2026-09-18T22:00:00.000Z",
"timeZone": "America/Denver" },
"technicianAssignments": [ { "membershipId": "mem_…", "assignedAt": "2026-09-17T15:00:00.000Z" } ],
"updatedAt": "2026-09-18T15:02:11.000Z"
}
Absent on purpose: customer email, quote price, options, margin, financing, payments, signatures, and any other customer of the company. See the data boundary.
Headers on every request
| Header | Direction | Notes |
|---|---|---|
x-api-key | request | Installer-company key, <keyId>.<secret> |
Idempotency-Key | request (writes) | Required on POST and PUT. Up to 128 characters of A-Z a-z 0-9 . _ : -. Same key + same body replays the original response; same key + different body or operation → 409. |
x-ridge-arc-api-version | response | Currently 2026-08-26 |
x-request-id | response | Quote it in support requests |
Change feed
jobs:readReturns job changes for your company in sequence order. Persist nextCursor and pass it back to continue; without a cursor the feed starts after sequence zero. limit 1 to 100.
{ "apiVersion": "2026-08-26",
"resources": [ { "sequence": 4182, "changedVersion": 7, "resource": { …job… } } ],
"nextCursor": "eyJj…", "hasMore": false }
jobs:readOne job. 404 if it is not assigned to your company.
Status events
jobs:status:write| Field | Rules |
|---|---|
status | one of ACKNOWLEDGED EN_ROUTE ON_SITE BLOCKED IN_PROGRESS COMPLETE |
occurredAt | ISO-8601 UTC; at most 5 minutes in the future, 30 days in the past |
note | optional, up to 2,000 characters; visible to the company |
blockerCode | required when BLOCKED: CUSTOMER_UNAVAILABLE SITE_NOT_READY MATERIAL_MISSING EQUIPMENT_DAMAGED PERMIT WEATHER SAFETY OTHER |
expectedVersion | the job version you last read; 409 if the job changed |
Allowed transitions:
ASSIGNED → ACKNOWLEDGED | BLOCKED
ACKNOWLEDGED → EN_ROUTE | ON_SITE | BLOCKED
EN_ROUTE → ON_SITE | BLOCKED
ON_SITE → IN_PROGRESS | BLOCKED | COMPLETE
BLOCKED → ACKNOWLEDGED | EN_ROUTE | ON_SITE | IN_PROGRESS
IN_PROGRESS → BLOCKED | COMPLETE
COMPLETE, CANCELLED → (terminal; CANCELLED is set by the company)
POST /api/partner/v1/jobs/job_…/status-events
x-api-key: … Idempotency-Key: 3b1f7e2c-…
{ "status": "BLOCKED", "blockerCode": "SITE_NOT_READY", "occurredAt": "2026-09-18T15:05:00Z",
"note": "Electrical panel not upgraded yet", "expectedVersion": 7 }
200 { "ok": true, "jobId": "job_…", "status": "BLOCKED", "version": 4,
"resourceVersion": 8, "occurredAt": "2026-09-18T15:05:00.000Z", "blockerCode": "SITE_NOT_READY" }
409 { "error": "Job changed; current version is 8" }
Schedule
jobs:schedule:write| Field | Rules |
|---|---|
status | TENTATIVE CONFIRMED CANCELLED |
startsAt, endsAt | ISO-8601 UTC or null; both required unless CANCELLED; end after start; a schedule that ended more than 30 days ago cannot be changed |
timeZone | IANA name (America/Denver); validated |
expectedVersion | job version |
A change made by either side emits install.schedule_changed to the other, so a company's dispatcher and your dispatch board converge.
Technicians and assignments
technicians:readYour company's technician memberships: id, display name, active flag. Use the membershipId in assignments.
jobs:assignment:writeBody { "membershipIds": [ … up to 20, unique … ], "expectedVersion": n }. Replaces the full assignment set; send an empty array to unassign everyone.
Documents
The install.document_available event carries document metadata. Agree the authorized retrieval mechanism during onboarding; a document event does not itself contain a download URL. The job resource above does not include a document list.
Scope acknowledgements
The install.scope_acknowledgement_required event identifies a changed scope and its version. Use the acknowledgement workflow authorized for your integration; a status-event write is not a scope acknowledgement.
Completion
A COMPLETE status event records installation progress. Evidence submission, quality review and financing approval are separate operations. The published Installer API has no photo-upload endpoint; agree the evidence interface and required fields with your partner. See the financing and QC integration design.
Webhooks for installers
The install.* family is listed on the webhooks page. A typical integration subscribes to install.job_assigned, install.schedule_changed, install.readiness_changed and install.scope_acknowledgement_required, and polls the change feed once a minute as a safety net.