ProBlu Developers: AI connector and API
ProBlu
ProBlu developers

Build on your ProBlu data

Your crews' daily logs, reports, photos, hours and change orders, available to AI assistants and to your own code. Everything is read-only and limited to your company.

Overview

ProBlu turns what field crews text into daily logs, field reports, timecards and change orders. There are two ways to use that data outside ProBlu:

AI connectorREST API
ForClaude, Codex, Cursor and other AI assistantsYour own scripts, reports and integrations
Addresshttps://api.problu.com/mcphttps://api.problu.com/v1
ProtocolModel Context Protocol (streamable HTTP)HTTPS + JSON
KeyAI connector keyAPI key

Both are included on every ProBlu plan while the account is active, and both are read-only: nothing can create, change or delete records.

Keys and access

A company admin creates keys in ProBlu under Integrations → AI and API access. An AI connector key only works with the AI connector, and an API key only works with the REST API. Each key is shown once, so store it like a password. Send it as Authorization: Bearer pb_live_….

Each key reads one company's data, limited to the kinds of data the admin picks:

DataIncludesOn by default
jobsJobs, addresses, status and crewYes
daily_logsDaily logs and their PDFsYes
reportsField reports, shared reports and their PDFsYes
photosJob photos and filesYes
timecardsTimecard entries and hoursYes
change_ordersChange orders, amounts and PDFsYes
peopleEmployee names and roles (no phone numbers or emails)Yes
admin_only_reportsReport types marked Admins only, such as internal walks of a super's jobNo

A key stops working when an admin revokes it, when the admin who created it loses admin access, or while the company's plan is paused.

Connect an AI tool

Create an AI connector in ProBlu, then add ProBlu to your tool as a remote MCP server:

Run in a terminal.

claude mcp add --transport http problu https://api.problu.com/mcp \
  --header "Authorization: Bearer $PROBLU_KEY"

Then ask things like “What held up the Green Bank job last week?” or “Total crew hours by job this month.” The AI picks the tools it needs.

Signing in to ChatGPT and Claude.ai with a ProBlu account, instead of pasting a key, is coming next.

REST quick start

Create an API key in ProBlu, then:

curl "https://api.problu.com/v1/daily-logs?since=2026-10-01&limit=10" \
  -H "Authorization: Bearer $PROBLU_API_KEY"

Every endpoint is a GET. The full list is in the reference below, and the OpenAPI spec works with code generators and API clients.

IDs, paging and dates

  • IDs are strings with a type prefix: job_123, dlog_456, frep_78, srep_12, media_901, time_3304, co_55, user_12. Pass them back exactly.
  • Lists return data and next_cursor. Pass cursor to get the next page and limit (1–100, default 25) to change its size. next_cursor is null on the last page.
  • Dates such as since, until and a log's date are YYYY-MM-DD in the company's time zone. Timestamps are ISO 8601 with a time zone.
  • Download links on photos and files expire after an hour. Ask for the record again to get a fresh one.
A list response
{
  "data": [
    {
      "id": "dlog_456",
      "job_id": "job_123",
      "date": "2026-10-01",
      "content": "Framed the north wall…"
    }
  ],
  "next_cursor": "eyJrIjoiMjAyNi0xMC0wMSIsImlkIjo0NTZ9"
}

Errors

Errors return an HTTP status and a stable code you can match on:

{
  "detail": {
    "code": "not_found",
    "message": "No daily log with that ID in this company."
  }
}
StatusCodeMeaning
401api_key_requiredNo key was sent. Send `Authorization: Bearer <key>`.
401invalid_api_keyThe key is wrong, mistyped or revoked.
401api_key_inactiveThe admin who created the key no longer has admin access.
403wrong_key_typeAn AI connector key was used with the REST API, or an API key with /mcp.
403insufficient_scopeThe key wasn't given access to this kind of data.
402trial_expired / plan_required / subscription_paused / billing_requiredThe company's plan doesn't allow API access right now.
404not_foundNo record with that ID in this company.
400invalid_id / invalid_cursor / invalid_date / invalid_limit / invalid_textA parameter isn't in the expected format.
429rate_limitedMore than 120 requests in a minute. Wait for Retry-After seconds.
503service_unavailable / pdf_unavailableTry again shortly.

AI connector tools return problems as a tool error the AI can read and correct, instead of an HTTP status.

Rate limits

Each key can make 120 requests a minute. Past that, requests get 429 rate_limited with a Retry-After header in seconds.

Your data

Your records stay in ProBlu. When an AI tool or script reads them with a key, the results go to that tool, and for AI tools to its AI provider under their terms. Test records, deleted records, storage paths, phone numbers and email addresses are never returned. ProBlu logs every request so admins can see how keys are used.

AI connector tools

The AI connector at https://api.problu.com/mcp offers these tools. An AI tool only sees the ones its key's data allows.

get_account

Which ProBlu company this connection reads, its timezone, and the data the key can see.

list_jobsjobs

List the company's jobs, newest first. Filter by status or by text in the job name, GC or address.

status · Job status, e.g. Active.query · Text to match in name, general contractor or address.limit · Page size (default 25).cursor · next_cursor from the previous call.
get_jobjobs

One job with its address, notes and assigned crew.

job_id required · Job ID, e.g. job_123.
search_daily_logsdaily_logs

Daily logs (what the crew did, manpower, milestones, answers to daily questions), newest date first. Filter by job, date range and text.

job_id · Only this job, e.g. job_123.since · Earliest date, YYYY-MM-DD.until · Latest date, YYYY-MM-DD.query · Text to match in the log.limit · Page size (default 25).cursor · next_cursor from the previous call.
get_daily_logdaily_logs

One daily log in full.

daily_log_id required · Daily log ID, e.g. dlog_456.
list_field_reportsreports

Field reports (inspections, site visits and other company-defined report types), newest first.

job_id · Only this job, e.g. job_123.since · Earliest date, YYYY-MM-DD.until · Latest date, YYYY-MM-DD.query · Text to match in the report.limit · Page size (default 25).cursor · next_cursor from the previous call.
get_field_reportreports

One field report in full.

field_report_id required · Field report ID, e.g. frep_78.
list_shared_reportsreports

Saved shared reports (the date-range packets sent to GCs and owners), with their written summaries.

job_id · Only this job, e.g. job_123.limit · Page size (default 25).cursor · next_cursor from the previous call.
get_shared_reportreports

One saved shared report with its day-by-day contents: each day's daily logs and field reports, plus change orders in the period when the key allows them.

shared_report_id required · Shared report ID, e.g. srep_12.
list_photosphotos

Photos, videos and files on jobs, newest first, with short-lived download links. Filter by job, daily log or field report.

job_id · Only this job, e.g. job_123.daily_log_id · Only media attached to this daily log.field_report_id · Only media attached to this field report.limit · Page size (default 25).cursor · next_cursor from the previous call.
get_photophotos

Show one photo as an image (a 512px preview) with its details.

photo_id required · Photo ID, e.g. media_901.
list_time_entriestimecards

Timecard entries with worked minutes, newest work date first. Filter by job, employee and date range.

job_id · Only this job, e.g. job_123.employee_id · Only this person, e.g. user_12.since · Earliest date, YYYY-MM-DD.until · Latest date, YYYY-MM-DD.limit · Page size (default 25).cursor · next_cursor from the previous call.
list_change_orderschange_orders

Change orders with status and total amount, newest first. Drafts are hidden unless status is Draft.

job_id · Only this job, e.g. job_123.status · Status, e.g. Executed, Unexecuted, Incomplete, Cancelled or Draft.limit · Page size (default 25).cursor · next_cursor from the previous call.
get_change_orderchange_orders

One change order with its priced line items.

change_order_id required · Change order ID, e.g. co_55.
list_peoplepeople

The company's people with their role (admin, office or field). No phone numbers or emails.

include_inactive · Include deactivated people.
search

Search jobs, daily logs and field reports by text. Returns ids to pass to fetch.

query required · What to look for.
fetch

Get the full text of a job, daily log or field report by an id from search.

id required · An id from search, e.g. dlog_456.

Account

GET /v1/me

The company and key in use

Returns the company this key reads, its timezone, and the kinds of data the key can see. Useful to check a key works.

Response fields and example
FieldTypeDescription
company_namestringThe company this key reads.
company_timezonestring or null
key_namestring or nullThe name the admin gave the key.
key_prefixstringThe first characters of the key, for recognizing it.
scopesarray of stringsKinds of data this key can read.
{
  "company_name": "Sandbox Framing",
  "company_timezone": "America/Denver",
  "key_name": "Payroll script",
  "key_prefix": "pb_live_Kd91",
  "scopes": [
    "jobs"
  ]
}

Jobs

GET /v1/jobs jobs

List jobs

Newest first. Filter by status, or by text in the job name, general contractor or address.

ParameterInDescription
statusqueryJob status, for example Active or Complete.
qqueryMatch job name, GC or address.
limitqueryPage size, 1-100 (default 25).
cursorquery`next_cursor` from the previous page.
Response fields and example
FieldTypeDescription
dataarray of objects
idstringJob ID, for example job_123.
namestring or nullJob name.
statusstring or nullJob status as set in ProBlu, for example Active or Complete.
general_contractorstring or nullGeneral contractor name.
addressobject
streetstring or null
citystring or null
statestring or null
zipstring or null
notesstring or nullJob notes shared with the crew.
created_atdate-time or nullWhen the job was created.
next_cursorstring or nullPass as `cursor` to get the next page; null when done.
{
  "data": [
    {
      "id": "job_123",
      "name": "Green Bank Remodel",
      "status": "Active",
      "general_contractor": "Summit Builders",
      "address": {
        "street": "410 Main St",
        "city": "Denver",
        "state": "CO",
        "zip": "80202"
      },
      "notes": "Gate code 4410. Park on 5th.",
      "created_at": "2026-10-01T15:04:05Z"
    }
  ],
  "next_cursor": "eyJrIjoiMjAyNi0xMC0wMSIsImlkIjo0NTZ9"
}
GET /v1/jobs/{job_id} jobs

Get a job

One job with its address, notes and currently assigned crew.

ParameterInDescription
job_id requiredpathThe record ID.
Response fields and example
FieldTypeDescription
idstringJob ID, for example job_123.
namestring or nullJob name.
statusstring or nullJob status as set in ProBlu, for example Active or Complete.
general_contractorstring or nullGeneral contractor name.
addressobject
streetstring or null
citystring or null
statestring or null
zipstring or null
notesstring or nullJob notes shared with the crew.
created_atdate-time or nullWhen the job was created.
crewarray of objectsPeople currently assigned to the job.
idstringPerson ID, for example user_12.
namestring or null
{
  "id": "job_123",
  "name": "Green Bank Remodel",
  "status": "Active",
  "general_contractor": "Summit Builders",
  "address": {
    "street": "410 Main St",
    "city": "Denver",
    "state": "CO",
    "zip": "80202"
  },
  "notes": "Gate code 4410. Park on 5th.",
  "created_at": "2026-10-01T15:04:05Z",
  "crew": [
    {
      "id": "user_12",
      "name": "Green Bank Remodel"
    }
  ]
}

Daily logs

GET /v1/daily-logs daily_logs

List daily logs

Newest log date first. Each log has what the crew wrote, structured work entries (work, people, hours), milestones and answers to the company's daily questions.

ParameterInDescription
job_idqueryOnly this job, for example job_123.
sincequeryEarliest date, YYYY-MM-DD.
untilqueryLatest date, YYYY-MM-DD.
qqueryMatch text in the log.
limitqueryPage size, 1-100 (default 25).
cursorquery`next_cursor` from the previous page.
Response fields and example
FieldTypeDescription
dataarray of objects
idstringDaily log ID, for example dlog_456.
job_idstringJob the log belongs to.
job_namestring or null
datedateThe work day the log covers, in the company's time zone.
authorobject or nullWho submitted the log.
idstringPerson ID, for example user_12.
namestring or null
contentstring or nullThe written daily log.
work_entriesarray of objectsStructured work, manpower and hours.
workstring or nullWhat was worked on.
peoplestring or nullNames or a headcount, as recorded.
total_hoursnumber or nullTotal crew hours for this work, when stated.
notesstring or nullExtra notes on this work.
milestonesarray of stringsMilestones reached that day.
questionsarray of objectsAnswers to the company's daily questions.
questionstring or nullOne of the company's daily questions.
answerstring or nullThe answer recorded for the day.
pdf_urlstringREST path to the PDF.
created_atdate-time
updated_atdate-timeLast edit.
next_cursorstring or nullPass as `cursor` to get the next page; null when done.
{
  "data": [
    {
      "id": "dlog_456",
      "job_id": "job_123",
      "job_name": "Green Bank Remodel",
      "date": "2026-10-01",
      "author": {
        "id": "user_12",
        "name": "Green Bank Remodel"
      },
      "content": "Framed the north wall and set two headers.",
      "work_entries": [
        {}
      ],
      "milestones": [
        "Walls sheathed"
      ],
      "questions": [
        {}
      ],
      "pdf_url": "/v1/daily-logs/dlog_456/pdf",
      "created_at": "2026-10-01T15:04:05Z",
      "updated_at": "2026-10-01T15:04:05Z"
    }
  ],
  "next_cursor": "eyJrIjoiMjAyNi0xMC0wMSIsImlkIjo0NTZ9"
}
GET /v1/daily-logs/{daily_log_id} daily_logs

Get a daily log

One daily log in full.

ParameterInDescription
daily_log_id requiredpathThe record ID.
Response fields and example
FieldTypeDescription
idstringDaily log ID, for example dlog_456.
job_idstringJob the log belongs to.
job_namestring or null
datedateThe work day the log covers, in the company's time zone.
authorobject or nullWho submitted the log.
idstringPerson ID, for example user_12.
namestring or null
contentstring or nullThe written daily log.
work_entriesarray of objectsStructured work, manpower and hours.
workstring or nullWhat was worked on.
peoplestring or nullNames or a headcount, as recorded.
total_hoursnumber or nullTotal crew hours for this work, when stated.
notesstring or nullExtra notes on this work.
milestonesarray of stringsMilestones reached that day.
questionsarray of objectsAnswers to the company's daily questions.
questionstring or nullOne of the company's daily questions.
answerstring or nullThe answer recorded for the day.
pdf_urlstringREST path to the PDF.
created_atdate-time
updated_atdate-timeLast edit.
{
  "id": "dlog_456",
  "job_id": "job_123",
  "job_name": "Green Bank Remodel",
  "date": "2026-10-01",
  "author": {
    "id": "user_12",
    "name": "Green Bank Remodel"
  },
  "content": "Framed the north wall and set two headers.",
  "work_entries": [
    {
      "work": "Framing",
      "people": "4",
      "total_hours": 8,
      "notes": "Gate code 4410. Park on 5th."
    }
  ],
  "milestones": [
    "Walls sheathed"
  ],
  "questions": [
    {
      "question": "Any safety issues?",
      "answer": "None reported"
    }
  ],
  "pdf_url": "/v1/daily-logs/dlog_456/pdf",
  "created_at": "2026-10-01T15:04:05Z",
  "updated_at": "2026-10-01T15:04:05Z"
}
GET /v1/daily-logs/{daily_log_id}/pdf daily_logs

Download a daily log PDF

The same branded PDF ProBlu emails, with photos.

ParameterInDescription
daily_log_id requiredpathThe record ID.

Returns application/pdf.

Field reports

GET /v1/field-reports reports

List field reports

Inspections, site walks and other report types the company defines. Admin-only report types need the admin_only_reports scope.

ParameterInDescription
job_idqueryOnly this job, for example job_123.
sincequeryEarliest date, YYYY-MM-DD.
untilqueryLatest date, YYYY-MM-DD.
qqueryMatch text in the report.
limitqueryPage size, 1-100 (default 25).
cursorquery`next_cursor` from the previous page.
Response fields and example
FieldTypeDescription
dataarray of objects
idstringField report ID, for example frep_78.
job_idstring
job_namestring or null
report_typestring or nullThe company-defined report type, for example Site Walk.
datedateThe day the report covers.
authorobject or null
idstringPerson ID, for example user_12.
namestring or null
contentstringThe written report.
pdf_urlstringREST path to the PDF.
created_atdate-time
updated_atdate-time
next_cursorstring or nullPass as `cursor` to get the next page; null when done.
{
  "data": [
    {
      "id": "frep_78",
      "job_id": "job_123",
      "job_name": "Green Bank Remodel",
      "report_type": "Site Walk",
      "date": "2026-10-01",
      "author": {
        "id": "user_12",
        "name": "Green Bank Remodel"
      },
      "content": "Framed the north wall and set two headers.",
      "pdf_url": "/v1/daily-logs/dlog_456/pdf",
      "created_at": "2026-10-01T15:04:05Z",
      "updated_at": "2026-10-01T15:04:05Z"
    }
  ],
  "next_cursor": "eyJrIjoiMjAyNi0xMC0wMSIsImlkIjo0NTZ9"
}
GET /v1/field-reports/{field_report_id} reports

Get a field report

One field report in full.

ParameterInDescription
field_report_id requiredpathThe record ID.
Response fields and example
FieldTypeDescription
idstringField report ID, for example frep_78.
job_idstring
job_namestring or null
report_typestring or nullThe company-defined report type, for example Site Walk.
datedateThe day the report covers.
authorobject or null
idstringPerson ID, for example user_12.
namestring or null
contentstringThe written report.
pdf_urlstringREST path to the PDF.
created_atdate-time
updated_atdate-time
{
  "id": "frep_78",
  "job_id": "job_123",
  "job_name": "Green Bank Remodel",
  "report_type": "Site Walk",
  "date": "2026-10-01",
  "author": {
    "id": "user_12",
    "name": "Green Bank Remodel"
  },
  "content": "Framed the north wall and set two headers.",
  "pdf_url": "/v1/daily-logs/dlog_456/pdf",
  "created_at": "2026-10-01T15:04:05Z",
  "updated_at": "2026-10-01T15:04:05Z"
}
GET /v1/field-reports/{field_report_id}/pdf reports

Download a field report PDF

The branded PDF with photos.

ParameterInDescription
field_report_id requiredpathThe record ID.

Returns application/pdf.

Shared reports

GET /v1/shared-reports reports

List shared reports

Saved date-range packets a company shares with GCs and owners, with their written summaries.

ParameterInDescription
job_idqueryOnly this job, for example job_123.
limitqueryPage size, 1-100 (default 25).
cursorquery`next_cursor` from the previous page.
Response fields and example
FieldTypeDescription
dataarray of objects
idstringShared report ID, for example srep_12.
job_idstring
job_namestring or null
titlestring or null
start_datedateFirst day covered.
end_datedateLast day covered.
summarystring or nullSaved written summary, when one was generated.
created_atdate-time
next_cursorstring or nullPass as `cursor` to get the next page; null when done.
{
  "data": [
    {
      "id": "srep_12",
      "job_id": "job_123",
      "job_name": "Green Bank Remodel",
      "title": "Last week on Green Bank",
      "start_date": "2026-10-01",
      "end_date": "2026-10-01",
      "summary": "Framing and sheathing finished; trusses started.",
      "created_at": "2026-10-01T15:04:05Z"
    }
  ],
  "next_cursor": "eyJrIjoiMjAyNi0xMC0wMSIsImlkIjo0NTZ9"
}
GET /v1/shared-reports/{shared_report_id} reports

Get a shared report

One shared report with its day-by-day contents (daily logs and field reports), plus change orders in the period when the key can read them.

ParameterInDescription
shared_report_id requiredpathThe record ID.
Response fields and example
FieldTypeDescription
idstringShared report ID, for example srep_12.
job_idstring
job_namestring or null
titlestring or null
start_datedateFirst day covered.
end_datedateLast day covered.
summarystring or nullSaved written summary, when one was generated.
created_atdate-time
daysarray of objectsDay-by-day contents, assembled live from the records like the Shared Reports page.
datedate
entriesarray of objects
idstringID of the daily log or field report.
kindstringdaily_log or field_report
report_typestring or nullField report type, for field reports.
authorobject or null
contentstring or null
milestonesarray of stringsMilestones reached that day.
change_ordersarray of objects or nullPresent only when the key can read change orders.
idstring
numberinteger or null
descriptionstring or null
statusstring or null
total_amountnumber or null
datedate or null
{
  "id": "srep_12",
  "job_id": "job_123",
  "job_name": "Green Bank Remodel",
  "title": "Last week on Green Bank",
  "start_date": "2026-10-01",
  "end_date": "2026-10-01",
  "summary": "Framing and sheathing finished; trusses started.",
  "created_at": "2026-10-01T15:04:05Z",
  "days": [
    {
      "date": "2026-10-01",
      "entries": [
        {}
      ]
    }
  ],
  "change_orders": [
    {
      "id": "co_55",
      "number": 101,
      "description": "Add LVL header at opening B",
      "status": "Active",
      "total_amount": 1250,
      "date": "2026-10-01"
    }
  ]
}

Photos

GET /v1/photos photos

List photos and files

Job photos, videos and documents, newest first, each with a download link that expires after an hour.

ParameterInDescription
job_idqueryOnly this job, for example job_123.
daily_log_idqueryOnly media on this daily log.
field_report_idqueryOnly media on this field report.
limitqueryPage size, 1-100 (default 25).
cursorquery`next_cursor` from the previous page.
Response fields and example
FieldTypeDescription
dataarray of objects
idstringPhoto or file ID, for example media_901.
job_idstring
daily_log_idstring or nullDaily log it is attached to, if any.
field_report_idstring or nullField report it is attached to, if any.
media_typestringimage, video or document
filenamestring or null
mime_typestring
size_bytesinteger or null
captured_atdate-time or nullWhen it was taken, when known.
created_atdate-time
urlstring or nullShort-lived download link.
next_cursorstring or nullPass as `cursor` to get the next page; null when done.
{
  "data": [
    {
      "id": "media_901",
      "job_id": "job_123",
      "daily_log_id": "dlog_456",
      "field_report_id": "frep_78",
      "media_type": "image",
      "filename": "north-wall.jpg",
      "mime_type": "image/jpeg",
      "size_bytes": 2,
      "captured_at": "2026-10-01T15:04:05Z",
      "created_at": "2026-10-01T15:04:05Z",
      "url": "https://storage.googleapis.com/…"
    }
  ],
  "next_cursor": "eyJrIjoiMjAyNi0xMC0wMSIsImlkIjo0NTZ9"
}
GET /v1/photos/{photo_id} photos

Get a photo or file

One photo or file with a fresh download link.

ParameterInDescription
photo_id requiredpathThe record ID.
Response fields and example
FieldTypeDescription
idstringPhoto or file ID, for example media_901.
job_idstring
daily_log_idstring or nullDaily log it is attached to, if any.
field_report_idstring or nullField report it is attached to, if any.
media_typestringimage, video or document
filenamestring or null
mime_typestring
size_bytesinteger or null
captured_atdate-time or nullWhen it was taken, when known.
created_atdate-time
urlstring or nullShort-lived download link.
{
  "id": "media_901",
  "job_id": "job_123",
  "daily_log_id": "dlog_456",
  "field_report_id": "frep_78",
  "media_type": "image",
  "filename": "north-wall.jpg",
  "mime_type": "image/jpeg",
  "size_bytes": 2,
  "captured_at": "2026-10-01T15:04:05Z",
  "created_at": "2026-10-01T15:04:05Z",
  "url": "https://storage.googleapis.com/…"
}

Timecards

GET /v1/time-entries timecards

List timecard entries

Newest work date first. worked_minutes already subtracts breaks. Entries on test logs and voided entries are left out.

ParameterInDescription
job_idqueryOnly this job, for example job_123.
employee_idqueryOnly this person, for example user_12.
sincequeryEarliest date, YYYY-MM-DD.
untilqueryLatest date, YYYY-MM-DD.
limitqueryPage size, 1-100 (default 25).
cursorquery`next_cursor` from the previous page.
Response fields and example
FieldTypeDescription
dataarray of objects
idstringTimecard entry ID, for example time_3304.
job_idstring
job_namestring or null
employeeobject or null
idstringPerson ID, for example user_12.
namestring or null
work_datedateThe work day.
started_atdate-time or nullClock-in time. Null for hours reported as a total.
ended_atdate-time or nullClock-out time. Null while clocked in or for reported totals.
break_minutesintegerUnpaid break minutes.
worked_minutesintegerMinutes worked after breaks. Still counting while clocked in.
statusstringopen or completed.
sourcestringHow it was recorded, for example assistant (by text) or webapp.
notesstring or null
next_cursorstring or nullPass as `cursor` to get the next page; null when done.
{
  "data": [
    {
      "id": "time_3304",
      "job_id": "job_123",
      "job_name": "Green Bank Remodel",
      "employee": {
        "id": "user_12",
        "name": "Green Bank Remodel"
      },
      "work_date": "2026-10-01",
      "started_at": "2026-10-01T15:04:05Z",
      "ended_at": "2026-10-01T15:04:05Z",
      "break_minutes": 480,
      "worked_minutes": 480,
      "status": "Active",
      "source": "assistant",
      "notes": "Gate code 4410. Park on 5th."
    }
  ],
  "next_cursor": "eyJrIjoiMjAyNi0xMC0wMSIsImlkIjo0NTZ9"
}

Change orders

GET /v1/change-orders change_orders

List change orders

Newest first. Drafts are hidden unless you ask for status=Draft.

ParameterInDescription
job_idqueryOnly this job, for example job_123.
statusqueryDrafts are hidden unless asked for.
limitqueryPage size, 1-100 (default 25).
cursorquery`next_cursor` from the previous page.
Response fields and example
FieldTypeDescription
dataarray of objects
idstringChange order ID, for example co_55.
numberinteger or nullThe change order number shown on the PDF.
job_idstring or null
job_namestring or null
descriptionstring or null
statusstring or nullDraft, Incomplete, Unexecuted, Executed or Cancelled.
total_amountnumber or nullTotal including markups.
schedule_extensionstring or nullSchedule impact, as written.
datedate or nullChange order date.
date_executeddate or nullWhen it was approved, if executed.
created_bystring or null
pdf_urlstringREST path to the PDF.
created_atdate-time or null
updated_atdate-time or null
next_cursorstring or nullPass as `cursor` to get the next page; null when done.
{
  "data": [
    {
      "id": "co_55",
      "number": 101,
      "job_id": "job_123",
      "job_name": "Green Bank Remodel",
      "description": "Add LVL header at opening B",
      "status": "Active",
      "total_amount": 1250,
      "schedule_extension": "1 day",
      "date": "2026-10-01",
      "date_executed": "2026-10-01",
      "created_by": "Sam Sandbox",
      "pdf_url": "/v1/daily-logs/dlog_456/pdf",
      "created_at": "2026-10-01T15:04:05Z",
      "updated_at": "2026-10-01T15:04:05Z"
    }
  ],
  "next_cursor": "eyJrIjoiMjAyNi0xMC0wMSIsImlkIjo0NTZ9"
}
GET /v1/change-orders/{change_order_id} change_orders

Get a change order

One change order with its priced line items, the same ones the PDF shows.

ParameterInDescription
change_order_id requiredpathThe record ID.
Response fields and example
FieldTypeDescription
idstringChange order ID, for example co_55.
numberinteger or nullThe change order number shown on the PDF.
job_idstring or null
job_namestring or null
descriptionstring or null
statusstring or nullDraft, Incomplete, Unexecuted, Executed or Cancelled.
total_amountnumber or nullTotal including markups.
schedule_extensionstring or nullSchedule impact, as written.
datedate or nullChange order date.
date_executeddate or nullWhen it was approved, if executed.
created_bystring or null
pdf_urlstringREST path to the PDF.
created_atdate-time or null
updated_atdate-time or null
line_itemsarray of objectsPriced line items, as shown on the PDF.
categorystringmaterials, labor, equipment or other.
namestring
unitstring or null
quantitynumber or null
unit_pricenumber or nullPrice per unit.
amountnumber or nullquantity × unit_price, before markups.
{
  "id": "co_55",
  "number": 101,
  "job_id": "job_123",
  "job_name": "Green Bank Remodel",
  "description": "Add LVL header at opening B",
  "status": "Active",
  "total_amount": 1250,
  "schedule_extension": "1 day",
  "date": "2026-10-01",
  "date_executed": "2026-10-01",
  "created_by": "Sam Sandbox",
  "pdf_url": "/v1/daily-logs/dlog_456/pdf",
  "created_at": "2026-10-01T15:04:05Z",
  "updated_at": "2026-10-01T15:04:05Z",
  "line_items": [
    {
      "category": "labor",
      "name": "Green Bank Remodel",
      "unit": "hr",
      "quantity": 8,
      "unit_price": 85,
      "amount": 1250
    }
  ]
}
GET /v1/change-orders/{change_order_id}/pdf change_orders

Download a change order PDF

The branded change order PDF.

ParameterInDescription
change_order_id requiredpathThe record ID.

Returns application/pdf.

People

GET /v1/people people

List people

Names and roles (admin, office or field). No phone numbers or emails.

ParameterInDescription
include_inactivequerytrue to include deactivated
Response fields and example
FieldTypeDescription
[
  {
    "id": "user_12",
    "name": "Green Bank Remodel",
    "role": "field",
    "active": true
  }
]