DevelopersAPI referenceService reports

Agreements API

REST endpoints for agreements in ServFlo: 5 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
A job's agreementsGET /organizations/{organizationId}/jobs/{jobId}/agreementsread
Prepare a job's agreementPOST /organizations/{organizationId}/jobs/{jobId}/agreementswrite
Send a job's agreement to signPOST /organizations/{organizationId}/jobs/{jobId}/agreements/sendsensitive
Record a client's agreement signaturePOST /organizations/{organizationId}/jobs/{jobId}/agreements/{agreementId}/signwrite
Withdraw an unsigned agreementPOST /organizations/{organizationId}/jobs/{jobId}/agreements/{agreementId}/voidsensitive

A job's agreements

GET /organizations/{organizationId}/jobs/{jobId}/agreements

The job's pre-service agreements (pending, signed with name, time and IP, or withdrawn) with the frozen wording. Technicians: their own jobs. Read-only.

PermissionserviceReports.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolagreements_listForJob (toolset serviceReports)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/agreements" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstring
jobIdstring
agreementTemplateIdstring or null
statusenumOne of PENDING, SIGNED, VOID.
titlestring
textstringThe exact wording, frozen when it was made (safe HTML).
textHashstring
signerNamestring or null
signerIpstring or null
signedAtstring (date-time) or null
signedByStaffboolean
sentAtstring (date-time) or null
urlstring or nullThe signing link while pending.

Prepare a job's agreement

POST /organizations/{organizationId}/jobs/{jobId}/agreements

The job's pending agreement, or a new one with its wording frozen now (the chosen template, else the service type's, else the default). Returns it with its signing link; nothing is sent (POST …/agreements/send sends it). Technicians: their own jobs (to sign on site).

PermissionserviceReports.write (Owner, Admin, Dispatcher, Technician)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolagreements_prepare (toolset serviceReports)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
agreementTemplateIdstring or nullNo

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/agreements" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agreementTemplateId":"agreementTemplate_id"}'

Response

201: the answer's fields
FieldTypeDescription
idstring
jobIdstring
agreementTemplateIdstring or null
statusenumOne of PENDING, SIGNED, VOID.
titlestring
textstringThe exact wording, frozen when it was made (safe HTML).
textHashstring
signerNamestring or null
signerIpstring or null
signedAtstring (date-time) or null
signedByStaffboolean
sentAtstring (date-time) or null
urlstring or nullThe signing link while pending.

Send a job's agreement to sign

POST /organizations/{organizationId}/jobs/{jobId}/agreements/send

Sends to the customer: emails and/or texts the job's customer the agreement's signing link (made as in POST …/agreements if needed). Consent and quiet hours apply. Returns the agreement and how each channel went.

PermissionserviceReports.publish (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 toolagreements_send (toolset serviceReports)
ApprovalOver MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals.

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
agreementTemplateIdstring or nullNo
channelsarray of enumNoDefault both; each is subject to the customer's consent and quiet hours. Up to 2 items.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/agreements/send" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agreementTemplateId":"agreementTemplate_id","channels":["EMAIL"]}'

Response

200: the answer's fields
FieldTypeDescription
agreementobject
agreement.idstring
agreement.jobIdstring
agreement.agreementTemplateIdstring or null
agreement.statusenumOne of PENDING, SIGNED, VOID.
agreement.titlestring
agreement.textstringThe exact wording, frozen when it was made (safe HTML).
agreement.textHashstring
agreement.signerNamestring or null
agreement.signerIpstring or null
agreement.signedAtstring (date-time) or null
agreement.signedByStaffboolean
agreement.sentAtstring (date-time) or null
agreement.urlstring or nullThe signing link while pending.
outcomesarray of object
outcomes[].channelenumOne of EMAIL, SMS.
outcomes[].accessIdstring or null
outcomes[].statusstringThe message's status: QUEUED, SENT, SENT_TEST, DEFERRED (quiet hours), SKIPPED (consent) …
outcomes[].messageIdstring or null
outcomes[].reasonstring or null

Record a client's agreement signature

POST /organizations/{organizationId}/jobs/{jobId}/agreements/{agreementId}/sign

The client signs on the technician's device (or on paper): typed name and an optional drawn signature (PNG data URL). Marked as recorded by staff. Pass the textHash of the wording the client was shown (GET …/agreements, or the offline packet): if the agreement's wording is no longer that, nothing is signed (409) and the client must be shown the current wording. 409 also when it is already signed or withdrawn. Re-checks the job's reports (one waiting for the agreement may open and be sent to the client). Emits agreement.signed. The technician app replays it with X-ServFlo-Occurred-At (signed when it happened).

PermissionserviceReports.write (Owner, Admin, Dispatcher, Technician)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolagreements_record (toolset serviceReports)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes
agreementIdpathstringYes

Request body

FieldTypeRequiredDescription
namestringYesThe signer's full name. Up to 200 characters.
signatureDataUrlstring or nullNoDrawn signature, PNG data URL.
textHashstring or nullNoThe agreement's textHash as the client was shown it. Recommended: a signature made against older wording is refused (409).

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/agreements/{agreementId}/sign" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield"}'

Response

200: the answer's fields
FieldTypeDescription
idstring
jobIdstring
agreementTemplateIdstring or null
statusenumOne of PENDING, SIGNED, VOID.
titlestring
textstringThe exact wording, frozen when it was made (safe HTML).
textHashstring
signerNamestring or null
signerIpstring or null
signedAtstring (date-time) or null
signedByStaffboolean
sentAtstring (date-time) or null
urlstring or nullThe signing link while pending.

Withdraw an unsigned agreement

POST /organizations/{organizationId}/jobs/{jobId}/agreements/{agreementId}/void

Withdraws a pending agreement: its link stops working. A signed agreement cannot be withdrawn (409).

PermissionserviceReports.publish (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 toolagreements_void (toolset serviceReports)
ApprovalOver MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals.

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes
agreementIdpathstringYes

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/agreements/{agreementId}/void" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
idstring
jobIdstring
agreementTemplateIdstring or null
statusenumOne of PENDING, SIGNED, VOID.
titlestring
textstringThe exact wording, frozen when it was made (safe HTML).
textHashstring
signerNamestring or null
signerIpstring or null
signedAtstring (date-time) or null
signedByStaffboolean
sentAtstring (date-time) or null
urlstring or nullThe signing link while pending.

On this page