Base URL: https://couplrfsm.com/api/v1. Conventions shared by every endpoint (examples, ids, dates, money) are on the API reference page. Errors, pagination and idempotency are in Errors, limits and retries.
List jobs#
GET /api/v1/jobs · requires the jobs:read ability
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
page |
integer | No | Default: 1. |
per_page |
integer | No | Values above 100 are served as 100. Default: 25. |
updated_since |
string (date-time) | No | Only records changed at or after this time. ISO 8601, for example 2026-11-14T15:00:00Z. |
customer_id |
integer | No | |
status |
string: open, completed |
No | open or completed. Any other value is ignored. |
scheduled_from |
string (date) | No | |
scheduled_to |
string (date) | No |
Example request
curl "https://couplrfsm.com/api/v1/jobs" \
-H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
"data": [
{
"id": 9312,
"customer_id": 1842,
"customer_name": "Dana Whitfield",
"job_type": "Repair",
"scheduled_date": "2026-12-02",
"scheduled_start_time": "09:00:00",
"time_window_start": null,
"time_window_end": null,
"duration_minutes": null,
"is_completed": false,
"completed_at": null,
"notes": "No cooling upstairs. Gate code 4410.",
"source": null,
"created_at": "2026-11-14T15:04:40+00:00",
"updated_at": "2026-11-14T15:04:40+00:00"
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 1,
"last_page": 1
}
}
Errors
| Status | When |
|---|---|
401 |
No key (api_key_missing), the key is unknown or revoked (api_key_invalid), the key had an end date that has passed (api_key_expired), or the key belongs to a private trial sandbox whose access window has ended (sandbox_expired). |
403 |
The key lacks the ability this endpoint needs (ability_missing), no admin user is left to act for the key (no_acting_admin), or the company's account is not yet verified. |
422 |
A parameter or field is invalid (validation_failed). errors maps each field to its messages. |
429 |
Too many requests (rate_limited). Wait Retry-After seconds. |
Create a job#
POST /api/v1/jobs · requires the jobs:write ability · accepts Idempotency-Key
Creating a job behaves as it does in the app: it appears on the
schedule, may be auto-dispatched to a technician, and fires the
job.created webhook. A second identical request (same customer, job
type and day) within 30 seconds returns the first job with 201
rather than creating another; send an Idempotency-Key for a longer
window.
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key |
string | No | Makes a retry of this request safe. See "Retries and idempotency". |
Request body (application/json)
Fields not listed are ignored. Every id must belong to the key's company.
| Field | Type | Required | Description |
|---|---|---|---|
customer_id |
integer | Yes | |
job_type_id |
integer | No | Required unless job_type is sent. |
job_type |
string | No | A job type name, matched case-insensitively. See GET /job-types. |
address_id |
integer or null | No | Required when the customer has more than one address. |
scheduled_date |
string (date) or null | No | Omit to leave the job unscheduled. |
scheduled_start_time |
string or null | No | Company-local time, e.g. 09:00. |
use_time_window |
boolean | No | true books an arrival window (time_window_*) instead of a start time. |
time_window_start |
string or null | No | |
time_window_end |
string or null | No | |
duration_minutes |
integer or null | No | |
days |
array of objects or null | No | A multi-day job, one entry per day, instead of scheduled_date. |
days[].date |
string (date) | No | |
days[].scheduled_start_time |
string or null | No | |
days[].time_window_start |
string or null | No | |
days[].time_window_end |
string or null | No | |
days[].duration_minutes |
integer or null | No | |
notes |
string or null | No | |
job_summary |
string or null | No | |
kind |
string: service, estimate |
No | An estimate visit must be scheduled. Default: service. |
estimate_id |
integer or null | No | The estimate an estimate visit is for. |
is_maintenance |
boolean | No | Links the job to the customer's active maintenance plan. |
market_segment_id |
integer or null | No | |
lead_source_id |
integer or null | No | |
branch_id |
integer or null | No | |
business_unit_id |
integer or null | No | |
assigned_tech_id |
integer or null | No | A single technician. Omit every technician field to auto-dispatch. |
assigned_tech_ids |
array of integers or null | No | |
lead_tech_id |
integer or null | No | |
tag_ids |
array of integers | No |
Example request
curl -X POST "https://couplrfsm.com/api/v1/jobs" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: YOUR_UNIQUE_KEY" \
-d '{"customer_id":1842,"job_type":"Repair","scheduled_date":"2026-12-02","scheduled_start_time":"09:00","notes":"No cooling upstairs. Gate code 4410."}'
Example response (201)
{
"data": {
"id": 9312,
"customer_id": 1842,
"customer_name": "Dana Whitfield",
"job_type": "Repair",
"scheduled_date": "2026-12-02",
"scheduled_start_time": "09:00:00",
"time_window_start": null,
"time_window_end": null,
"duration_minutes": null,
"is_completed": false,
"completed_at": null,
"notes": "No cooling upstairs. Gate code 4410.",
"source": null,
"created_at": "2026-11-14T15:04:40+00:00",
"updated_at": "2026-11-14T15:04:40+00:00"
}
}
Errors
| Status | When |
|---|---|
401 |
No key (api_key_missing), the key is unknown or revoked (api_key_invalid), the key had an end date that has passed (api_key_expired), or the key belongs to a private trial sandbox whose access window has ended (sandbox_expired). |
403 |
The key lacks the ability this endpoint needs (ability_missing), no admin user is left to act for the key (no_acting_admin), or the company's account is not yet verified. |
422 |
A parameter or field is invalid (validation_failed). errors maps each field to its messages. |
429 |
Too many requests (rate_limited). Wait Retry-After seconds. |
Get a job#
GET /api/v1/jobs/{id} · requires the jobs:read ability
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes |
Example request
curl "https://couplrfsm.com/api/v1/jobs/1842" \
-H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
"data": {
"id": 9312,
"customer_id": 1842,
"customer_name": "Dana Whitfield",
"job_type": "Repair",
"scheduled_date": "2026-12-02",
"scheduled_start_time": "09:00:00",
"time_window_start": null,
"time_window_end": null,
"duration_minutes": null,
"is_completed": false,
"completed_at": null,
"notes": "No cooling upstairs. Gate code 4410.",
"source": null,
"created_at": "2026-11-14T15:04:40+00:00",
"updated_at": "2026-11-14T15:04:40+00:00"
}
}
Errors
| Status | When |
|---|---|
401 |
No key (api_key_missing), the key is unknown or revoked (api_key_invalid), the key had an end date that has passed (api_key_expired), or the key belongs to a private trial sandbox whose access window has ended (sandbox_expired). |
403 |
The key lacks the ability this endpoint needs (ability_missing), no admin user is left to act for the key (no_acting_admin), or the company's account is not yet verified. |
404 |
No such record in this company (not_found). |
429 |
Too many requests (rate_limited). Wait Retry-After seconds. |
Update a job#
PATCH /api/v1/jobs/{id} · requires the jobs:write ability · accepts Idempotency-Key
Reschedule a job, move it to another of the customer's addresses,
change the crew or edit its notes. Only the fields you send change.
The customer cannot be changed. A job is completed with
POST /jobs/{id}/complete and cannot be deleted through the API.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes |
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key |
string | No | Makes a retry of this request safe. See "Retries and idempotency". |
Request body (application/json)
Fields not listed are ignored. Every id must belong to the key's company.
| Field | Type | Required | Description |
|---|---|---|---|
job_type_id |
integer | No | |
job_type |
string | No | A job type name, matched case-insensitively. See GET /job-types. |
address_id |
integer or null | No | One of the job's customer's addresses. |
scheduled_date |
string (date) | No | Moves a single-day job to this day. |
scheduled_start_time |
string or null | No | Company-local time, e.g. 13:00. |
use_time_window |
boolean | No | true books an arrival window (time_window_*) instead of a start time. |
time_window_start |
string or null | No | |
time_window_end |
string or null | No | |
duration_minutes |
integer or null | No | |
days |
array of objects | No | Replaces the job's days with this list, for a multi-day job. |
days[].date |
string (date) | No | |
days[].scheduled_start_time |
string or null | No | |
days[].time_window_start |
string or null | No | |
days[].time_window_end |
string or null | No | |
days[].duration_minutes |
integer or null | No | |
unschedule |
boolean | No | true takes the job off the calendar. Not allowed for estimate visits or completed jobs. |
notes |
string or null | No | |
job_summary |
string or null | No | |
market_segment_id |
integer or null | No | |
lead_source_id |
integer or null | No | |
branch_id |
integer or null | No | |
business_unit_id |
integer or null | No | |
assigned_tech_ids |
array of integers | No | Replaces the crew. An empty list clears it. See GET /technicians. |
lead_tech_id |
integer or null | No | Sent with assigned_tech_ids. |
Example request
curl -X PATCH "https://couplrfsm.com/api/v1/jobs/1842" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: YOUR_UNIQUE_KEY" \
-d '{"scheduled_date":"2026-12-04","scheduled_start_time":"13:00"}'
Example response (200)
{
"data": {
"id": 9312,
"customer_id": 1842,
"customer_name": "Dana Whitfield",
"job_type": "Repair",
"scheduled_date": "2026-12-02",
"scheduled_start_time": "09:00:00",
"time_window_start": null,
"time_window_end": null,
"duration_minutes": null,
"is_completed": false,
"completed_at": null,
"notes": "No cooling upstairs. Gate code 4410.",
"source": null,
"created_at": "2026-11-14T15:04:40+00:00",
"updated_at": "2026-11-14T15:04:40+00:00"
}
}
Errors
| Status | When |
|---|---|
401 |
No key (api_key_missing), the key is unknown or revoked (api_key_invalid), the key had an end date that has passed (api_key_expired), or the key belongs to a private trial sandbox whose access window has ended (sandbox_expired). |
403 |
The key lacks the ability this endpoint needs (ability_missing), no admin user is left to act for the key (no_acting_admin), or the company's account is not yet verified. |
404 |
No such record in this company (not_found). |
422 |
A parameter or field is invalid (validation_failed). errors maps each field to its messages. |
429 |
Too many requests (rate_limited). Wait Retry-After seconds. |
Complete a job#
POST /api/v1/jobs/{id}/complete · requires the jobs:complete ability · accepts Idempotency-Key
Marks a job done, the same as completing it in the apps. The
job.completed event is delivered (estimate.completed for an
estimate visit) and the crew is credited for the work.
The customer may be contacted. Completing a job sends whatever the company has switched on for a finished job: the completion text and, if the company asks for reviews automatically, a review request. That is why this has its own ability.
notes, if sent, is added to the job's notes log.
Refused with 422 on job when the job is already completed; when
it is a maintenance plan visit; when an invoice is being held until
the job is done; or when the job type has a checklist that must be
filled in. Complete those in Couplr.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes |
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key |
string | No | Makes a retry of this request safe. See "Retries and idempotency". |
Request body (application/json)
Fields not listed are ignored.
| Field | Type | Required | Description |
|---|---|---|---|
notes |
string or null | No | Added to the job's notes log. |
Example request
curl -X POST "https://couplrfsm.com/api/v1/jobs/1842/complete" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: YOUR_UNIQUE_KEY" \
-d '{"notes":"Replaced the capacitor. System cooling normally."}'
Example response (200)
{
"data": {
"id": 9312,
"customer_id": 1842,
"customer_name": "Dana Whitfield",
"job_type": "Repair",
"scheduled_date": "2026-12-02",
"scheduled_start_time": "09:00:00",
"time_window_start": null,
"time_window_end": null,
"duration_minutes": null,
"is_completed": false,
"completed_at": null,
"notes": "No cooling upstairs. Gate code 4410.",
"source": null,
"created_at": "2026-11-14T15:04:40+00:00",
"updated_at": "2026-11-14T15:04:40+00:00"
}
}
Errors
| Status | When |
|---|---|
401 |
No key (api_key_missing), the key is unknown or revoked (api_key_invalid), the key had an end date that has passed (api_key_expired), or the key belongs to a private trial sandbox whose access window has ended (sandbox_expired). |
403 |
The key lacks the ability this endpoint needs (ability_missing), no admin user is left to act for the key (no_acting_admin), or the company's account is not yet verified. |
404 |
No such record in this company (not_found). |
422 |
A parameter or field is invalid (validation_failed). errors maps each field to its messages. |
429 |
Too many requests (rate_limited). Wait Retry-After seconds. |
Job object#
| Field | Type | Description |
|---|---|---|
id |
integer | |
customer_id |
integer | |
customer_name |
string or null | |
job_type |
string or null | |
scheduled_date |
string (date) or null | |
scheduled_start_time |
string or null | Company-local time of day, HH:MM:SS. |
time_window_start |
string or null | Company-local time of day. |
time_window_end |
string or null | Company-local time of day. |
duration_minutes |
integer or null | |
is_completed |
boolean | |
completed_at |
string or null | YYYY-MM-DD HH:MM:SS in UTC (not ISO 8601). |
notes |
string or null | |
source |
string or null | |
created_at |
string (date-time) or null | |
updated_at |
string (date-time) or null |