Lien waivers
Conditional and unconditional, progress and final. Tracked per vendor per pay app so nothing gets paid blind.
The lien_waiver object
Every object carries an id, timestamps, and an audit_trail. Money is integer cents. Expand any node in the explorer to see how it links to the rest of the record.
- idstringUnique, stable identifier. Prefixed by object type.
- objectstringString naming the object type.
- projectstringProject ID.
- pay_appstringPay app it covers.
- vendorstringVendor ID.
- typeenumconditional_progress · unconditional_progress · conditional_final · unconditional_final.
- amountintegerAmount waived, cents.
- statusenumrequested · missing · received · rejected.
- filestringSigned document file ID.
- received_attimestampWhen it arrived.
- created_attimestampISO 8601, UTC.
- updated_attimestampISO 8601, UTC. Changes on every write.
- audit_trailstringPath to the append-only history of who changed what, and when.
lien_waiver · sample data
object{14}
- id"lw_9_volt"id
- object"lien_waiver"id
- project"prj_24118"id
- pay_app"pa_9"id
- vendor"vnd_volt_electric"id
- vendor_name"Volt Electric"string
- type"conditional_progress"string
- amount4338000integer$43,380.00
- status"received"string
- file"file_lw9volt"id
- received_at
- created_at
- updated_at
- audit_trail"/v1/lien-waivers/lw_9_volt/audit"string
GET
/v1/lien-waiversList lien waivers
Filter to status=missing before you cut checks.
Parameters
- pay_appstringqueryPay app ID.
- statusenumqueryStatus filter.
- limitintegerqueryPage size, 1 to 100. Default 25.
- cursorstringqueryCursor from a previous page’s next_cursor.
Returns
A paginated list of lien_waiver objects. Errors use the standard error shape.
Request
curl https://api.os.construction/v1/lien-waivers \
-H "Authorization: Bearer $OS_API_KEY"const res = await fetch("https://api.os.construction/v1/lien-waivers", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.OS_API_KEY}`,
},
});
const page = await res.json();import os, uuid, requests
res = requests.get(
"https://api.os.construction/v1/lien-waivers",
headers={
"Authorization": f"Bearer {os.environ['OS_API_KEY']}",
},
)
res.raise_for_status()
data = res.json()Response · 200
{
"object": "list",
"url": "/v1/lien-waivers",
"has_more": false,
"next_cursor": null,
"data": [
{
"id": "lw_9_apex",
"object": "lien_waiver",
"project": "prj_24118",
"pay_app": "pa_9",
"vendor": "vnd_apex_steel",
"vendor_name": "Apex Steel",
"type": "conditional_progress",
"amount": 4338000,
"status": "missing",
"file": null,
"received_at": null,
"created_at": "2026-09-30T22:00:00Z",
"updated_at": "2026-10-02T17:45:00Z",
"audit_trail": "/v1/lien-waivers/lw_9_apex/audit"
},
{
"id": "lw_9_volt",
"object": "lien_waiver",
"project": "prj_24118",
"pay_app": "pa_9",
"vendor": "vnd_volt_electric",
"vendor_name": "Volt Electric",
"type": "conditional_progress",
"amount": 4338000,
"status": "received",
"file": "file_lw9volt",
"received_at": "2026-10-02T17:45:00Z",
"created_at": "2026-09-30T22:00:00Z",
"updated_at": "2026-10-02T17:45:00Z",
"audit_trail": "/v1/lien-waivers/lw_9_volt/audit"
}
]
}PATCH
/v1/lien-waivers/{id}Record a received waiver
Attach the signed file and mark received.
Idempotent. Send an Idempotency-Key; retries within 24 hours return the original result and never write twice.
Parameters
- idstringpathrequiredThe lien waiver ID, e.g. lw_9_volt.
- Idempotency-KeystringheaderrequiredAny unique string. Replays return the first result instead of writing twice.
- statusenumbodyrequiredNew status.
- filestringbodyFile ID.
Returns
The lien_waiver object. Errors use the standard error shape.
Request
curl -X PATCH https://api.os.construction/v1/lien-waivers/lw_9_volt \
-H "Authorization: Bearer $OS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"status": "received",
"file": "file_lw9volt"
}'const res = await fetch("https://api.os.construction/v1/lien-waivers/lw_9_volt", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.OS_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"status": "received",
"file": "file_lw9volt"
}),
});
const obj = await res.json();import os, uuid, requests
res = requests.patch(
"https://api.os.construction/v1/lien-waivers/lw_9_volt",
headers={
"Authorization": f"Bearer {os.environ['OS_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"status": "received",
"file": "file_lw9volt"
},
)
res.raise_for_status()
data = res.json()Response · 200
{
"id": "lw_9_volt",
"object": "lien_waiver",
"project": "prj_24118",
"pay_app": "pa_9",
"vendor": "vnd_volt_electric",
"vendor_name": "Volt Electric",
"type": "conditional_progress",
"amount": 4338000,
"status": "received",
"file": "file_lw9volt",
"received_at": "2026-10-02T17:45:00Z",
"created_at": "2026-09-30T22:00:00Z",
"updated_at": "2026-10-02T17:45:00Z",
"audit_trail": "/v1/lien-waivers/lw_9_volt/audit"
}Events
Webhooks fire on every state change of a lien_waiver.