DevelopersAPI referenceProjects

Subcontracts API

REST endpoints for subcontracts in ServFlo: 12 operations with parameters, request and response fields, permissions and curl examples.

Base URL: https://app.servflo.ai/api. Every call needs Authorization: Bearer sfk_… (Authentication); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id.

OperationEndpointRisk
Subcontractor bids, bills and payments on a projectGET /organizations/{organizationId}/projects/{projectId}/subcontractsread
Record a sub's bidPOST /organizations/{organizationId}/projects/{projectId}/subcontracts/bidswrite
Accept, decline or change a bidPATCH /organizations/{organizationId}/projects/{projectId}/subcontracts/bids/{bidId}write
Delete a bidDELETE /organizations/{organizationId}/projects/{projectId}/subcontracts/bids/{bidId}sensitive
Record a sub's billPOST /organizations/{organizationId}/projects/{projectId}/subcontracts/billswrite
Change a sub's billPATCH /organizations/{organizationId}/projects/{projectId}/subcontracts/bills/{billId}write
Delete a sub's billDELETE /organizations/{organizationId}/projects/{projectId}/subcontracts/bills/{billId}sensitive
Record a payment to a subPOST /organizations/{organizationId}/projects/{projectId}/subcontracts/bills/{billId}/paymentswrite
Delete a recorded payment to a subDELETE /organizations/{organizationId}/projects/{projectId}/subcontracts/payments/{subPaymentId}sensitive
Subcontractors' view-only linksGET /organizations/{organizationId}/projects/{projectId}/sub-linksread
Give a sub a view-only linkPOST /organizations/{organizationId}/projects/{projectId}/sub-linkssensitive
Turn off a sub's linkPOST /organizations/{organizationId}/projects/{projectId}/sub-links/revokesensitive

Subcontractor bids, bills and payments on a project

GET /organizations/{organizationId}/projects/{projectId}/subcontracts

Bids (accepted ones are committed), bills with the payments recorded and lien waivers, and per sub: committed, billed, paid and owed. ServFlo records payments; it never pays a sub. Read-only.

Permissionsubcontractors.bills (Owner, Admin)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolsubcontracts_get (toolset projects)

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/subcontracts" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
bidsarray of object
bids[].idstring
bids[].vendorIdstring
bids[].amountCentsinteger
bids[].statusstring
billsarray of object
bills[].idstring
bills[].vendorIdstring
bills[].amountCentsinteger
bills[].paidCentsinteger
bills[].owedCentsinteger
bills[].paymentsarray of object
bills[].payments[].idstring
bills[].payments[].amountCentsinteger
bills[].payments[].hasLienWaiverboolean
bySubcontractorarray of object
bySubcontractor[].vendorIdstring
bySubcontractor[].owedCentsinteger
totalsobject
totals.owedCentsinteger

Record a sub's bid

POST /organizations/{organizationId}/projects/{projectId}/subcontracts/bids

A subcontractor's price for work on the project (optionally a phase). Accept it with PATCH …/bids/{bidId}.

Permissionsubcontractors.bills (Owner, Admin)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolsubcontracts_addBid (toolset projects)

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).

Request body

FieldTypeRequiredDescription
vendorIdstringYesThe subcontractor (a vendor; GET /subcontractors).
phaseIdstring or nullNo
amountCentsintegerYesMoney in integer cents (12500 = 125.00). -100000000–100000000.
scopestring or nullNoUp to 5000 characters.
receivedOnempty string or string or nullNo

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/subcontracts/bids" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"vendorId":"vendor_id","amountCents":12500}'

Response

201: the answer's fields
FieldTypeDescription
bidsarray of object
bids[].idstring
bids[].vendorIdstring
bids[].amountCentsinteger
bids[].statusstring
billsarray of object
bills[].idstring
bills[].vendorIdstring
bills[].amountCentsinteger
bills[].paidCentsinteger
bills[].owedCentsinteger
bills[].paymentsarray of object
bills[].payments[].idstring
bills[].payments[].amountCentsinteger
bills[].payments[].hasLienWaiverboolean
bySubcontractorarray of object
bySubcontractor[].vendorIdstring
bySubcontractor[].owedCentsinteger
totalsobject
totals.owedCentsinteger

Accept, decline or change a bid

PATCH /organizations/{organizationId}/projects/{projectId}/subcontracts/bids/{bidId}

ACCEPTED commits the amount (and puts the sub on the bid's phase when it has none); DECLINED; or change the amount, scope or phase.

Permissionsubcontractors.bills (Owner, Admin)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolsubcontracts_updateBid (toolset projects)

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).
bidIdpathstringYes

Request body

FieldTypeRequiredDescription
statusenumNoOne of SUBMITTED, ACCEPTED, DECLINED.
amountCentsintegerNoMoney in integer cents (12500 = 125.00). -100000000–100000000.
scopestring or nullNoUp to 5000 characters.
phaseIdstring or nullNo

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/subcontracts/bids/{bidId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"SUBMITTED","amountCents":12500,"scope":"string"}'

Response

200: the answer's fields
FieldTypeDescription
bidsarray of object
bids[].idstring
bids[].vendorIdstring
bids[].amountCentsinteger
bids[].statusstring
billsarray of object
bills[].idstring
bills[].vendorIdstring
bills[].amountCentsinteger
bills[].paidCentsinteger
bills[].owedCentsinteger
bills[].paymentsarray of object
bills[].payments[].idstring
bills[].payments[].amountCentsinteger
bills[].payments[].hasLienWaiverboolean
bySubcontractorarray of object
bySubcontractor[].vendorIdstring
bySubcontractor[].owedCentsinteger
totalsobject
totals.owedCentsinteger

Delete a bid

DELETE /organizations/{organizationId}/projects/{projectId}/subcontracts/bids/{bidId}

Destructive: removes a subcontractor's bid from the project (an accepted bid stops counting as committed).

Permissionsubcontractors.bills (Owner, Admin)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolsubcontracts_deleteBid (toolset projects)
ApprovalOver MCP, this tool always waits for your approval in ServFlo. See Approvals.

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).
bidIdpathstringYes

Example

curl -X DELETE "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/subcontracts/bids/{bidId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
bidsarray of object
bids[].idstring
bids[].vendorIdstring
bids[].amountCentsinteger
bids[].statusstring
billsarray of object
bills[].idstring
bills[].vendorIdstring
bills[].amountCentsinteger
bills[].paidCentsinteger
bills[].owedCentsinteger
bills[].paymentsarray of object
bills[].payments[].idstring
bills[].payments[].amountCentsinteger
bills[].payments[].hasLienWaiverboolean
bySubcontractorarray of object
bySubcontractor[].vendorIdstring
bySubcontractor[].owedCentsinteger
totalsobject
totals.owedCentsinteger

Record a sub's bill

POST /organizations/{organizationId}/projects/{projectId}/subcontracts/bills

What a subcontractor billed for the project: it counts in SUBCONTRACTORS actuals and in what the sub is owed.

Permissionsubcontractors.bills (Owner, Admin)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolsubcontracts_addBill (toolset projects)

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).

Request body

FieldTypeRequiredDescription
vendorIdstringYesThe subcontractor (a vendor; GET /subcontractors).
phaseIdstring or nullNo
numberstring or nullNoUp to 100 characters.
billDateempty string or string or nullNo
dueDateempty string or string or nullNo
amountCentsintegerYesMoney in integer cents (12500 = 125.00). -100000000–100000000.
descriptionstring or nullNoUp to 5000 characters.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/subcontracts/bills" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"vendorId":"vendor_id","amountCents":12500}'

Response

201: the answer's fields
FieldTypeDescription
bidsarray of object
bids[].idstring
bids[].vendorIdstring
bids[].amountCentsinteger
bids[].statusstring
billsarray of object
bills[].idstring
bills[].vendorIdstring
bills[].amountCentsinteger
bills[].paidCentsinteger
bills[].owedCentsinteger
bills[].paymentsarray of object
bills[].payments[].idstring
bills[].payments[].amountCentsinteger
bills[].payments[].hasLienWaiverboolean
bySubcontractorarray of object
bySubcontractor[].vendorIdstring
bySubcontractor[].owedCentsinteger
totalsobject
totals.owedCentsinteger

Change a sub's bill

PATCH /organizations/{organizationId}/projects/{projectId}/subcontracts/bills/{billId}

Number, dates, amount (not below what was paid), description or phase.

Permissionsubcontractors.bills (Owner, Admin)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolsubcontracts_updateBill (toolset projects)

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).
billIdpathstringYes

Request body

FieldTypeRequiredDescription
phaseIdstring or nullNo
numberstring or nullNoUp to 100 characters.
billDatestringNoA calendar date in the business's own calendar, YYYY-MM-DD.
dueDateempty string or string or nullNo
amountCentsintegerNoMoney in integer cents (12500 = 125.00). -100000000–100000000.
descriptionstring or nullNoUp to 5000 characters.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/subcontracts/bills/{billId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phaseId":"phase_id","number":"string","billDate":"2026-11-03"}'

Response

200: the answer's fields
FieldTypeDescription
bidsarray of object
bids[].idstring
bids[].vendorIdstring
bids[].amountCentsinteger
bids[].statusstring
billsarray of object
bills[].idstring
bills[].vendorIdstring
bills[].amountCentsinteger
bills[].paidCentsinteger
bills[].owedCentsinteger
bills[].paymentsarray of object
bills[].payments[].idstring
bills[].payments[].amountCentsinteger
bills[].payments[].hasLienWaiverboolean
bySubcontractorarray of object
bySubcontractor[].vendorIdstring
bySubcontractor[].owedCentsinteger
totalsobject
totals.owedCentsinteger

Delete a sub's bill

DELETE /organizations/{organizationId}/projects/{projectId}/subcontracts/bills/{billId}

Destructive: removes a bill without payments.

Permissionsubcontractors.bills (Owner, Admin)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolsubcontracts_deleteBill (toolset projects)
ApprovalOver MCP, this tool always waits for your approval in ServFlo. See Approvals.

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).
billIdpathstringYes

Example

curl -X DELETE "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/subcontracts/bills/{billId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
bidsarray of object
bids[].idstring
bids[].vendorIdstring
bids[].amountCentsinteger
bids[].statusstring
billsarray of object
bills[].idstring
bills[].vendorIdstring
bills[].amountCentsinteger
bills[].paidCentsinteger
bills[].owedCentsinteger
bills[].paymentsarray of object
bills[].payments[].idstring
bills[].payments[].amountCentsinteger
bills[].payments[].hasLienWaiverboolean
bySubcontractorarray of object
bySubcontractor[].vendorIdstring
bySubcontractor[].owedCentsinteger
totalsobject
totals.owedCentsinteger

Record a payment to a sub

POST /organizations/{organizationId}/projects/{projectId}/subcontracts/bills/{billId}/payments

Records a payment the business made outside ServFlo (check, ACH, cash, card): NEVER moves money. Not more than is left on the bill. Attach the lien waiver with POST …/files (category LIEN_WAIVER, subPaymentId).

Permissionsubcontractors.bills (Owner, Admin)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolsubcontracts_recordPayment (toolset projects)

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).
billIdpathstringYes

Request body

FieldTypeRequiredDescription
amountCentsintegerYesMoney in integer cents (12500 = 125.00). -100000000–100000000.
paidOnempty string or string or nullNo
methodenumNoOne of CHECK, ACH, CASH, CARD, OTHER. Default CHECK.
referencestring or nullNoUp to 100 characters.
notestring or nullNoUp to 2000 characters.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/subcontracts/bills/{billId}/payments" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amountCents":12500}'

Response

201: the answer's fields
FieldTypeDescription
bidsarray of object
bids[].idstring
bids[].vendorIdstring
bids[].amountCentsinteger
bids[].statusstring
billsarray of object
bills[].idstring
bills[].vendorIdstring
bills[].amountCentsinteger
bills[].paidCentsinteger
bills[].owedCentsinteger
bills[].paymentsarray of object
bills[].payments[].idstring
bills[].payments[].amountCentsinteger
bills[].payments[].hasLienWaiverboolean
bySubcontractorarray of object
bySubcontractor[].vendorIdstring
bySubcontractor[].owedCentsinteger
totalsobject
totals.owedCentsinteger
paymentIdstring

Delete a recorded payment to a sub

DELETE

/organizations/{organizationId}/projects/{projectId}/subcontracts/payments/{subPaymentId}

Destructive: removes a recorded payment (its lien waiver stays in the files).

Permissionsubcontractors.bills (Owner, Admin)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolsubcontracts_deletePayment (toolset projects)
ApprovalOver MCP, this tool always waits for your approval in ServFlo. See Approvals.

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).
subPaymentIdpathstringYes

Example

curl -X DELETE "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/subcontracts/payments/{subPaymentId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
bidsarray of object
bids[].idstring
bids[].vendorIdstring
bids[].amountCentsinteger
bids[].statusstring
billsarray of object
bills[].idstring
bills[].vendorIdstring
bills[].amountCentsinteger
bills[].paidCentsinteger
bills[].owedCentsinteger
bills[].paymentsarray of object
bills[].payments[].idstring
bills[].payments[].amountCentsinteger
bills[].payments[].hasLienWaiverboolean
bySubcontractorarray of object
bySubcontractor[].vendorIdstring
bySubcontractor[].owedCentsinteger
totalsobject
totals.owedCentsinteger
GET /organizations/{organizationId}/projects/{projectId}/sub-links

The live view-only links of subs on the project. Read-only.

Permissionsubcontractors.read (Owner, Admin, Dispatcher, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolsubcontracts_links (toolset projects)

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/sub-links" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstring
vendorIdstring
urlstring
POST /organizations/{organizationId}/projects/{projectId}/sub-links

Grants access: a link (/sub/{token}) where the subcontractor sees the project's name and address, their phases and the files shared with subs; never prices or the customer's details. Returns the live link when there is one.

Permissionsubcontractors.manage (Owner, Admin, Dispatcher)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolsubcontracts_createLink (toolset projects)
ApprovalOver MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals.

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).

Request body

FieldTypeRequiredDescription
vendorIdstringYesThe subcontractor (a vendor; GET /subcontractors).

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/sub-links" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"vendorId":"vendor_id"}'

Response

201: the answer's fields
FieldTypeDescription
idstring
urlstring
POST /organizations/{organizationId}/projects/{projectId}/sub-links/revoke

Revokes access: the sub's link stops working.

Permissionsubcontractors.manage (Owner, Admin, Dispatcher)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolsubcontracts_revokeLink (toolset projects)
ApprovalOver MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals.

Parameters

NameInTypeRequiredDescription
projectIdpathstringYesThe project (GET /projects).

Request body

FieldTypeRequiredDescription
vendorIdstringYesThe subcontractor (a vendor; GET /subcontractors).

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/projects/{projectId}/sub-links/revoke" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"vendorId":"vendor_id"}'

Response

200: the answer's fields
FieldTypeDescription
oktrue

On this page