Skip to content

Link or unlink what an invoice bills

POST
/invoices/{id}/billing-source
curl --request POST \
--url https://app.buildworkpro.com/api/v1/invoices/1/billing-source \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "sourcePayAppId": 1, "paymentTermInstallmentId": 1, "sourceBidId": 1, "dryRun": true }'

Attach an existing invoice to the pay application, payment-schedule installment and/or bid it bills, or detach it (send null). Allowed in every status except voided, so an imported, manual or already-paid invoice can be linked after the fact; only the link columns and the derived sourceType change — never lines, totals or status — and nothing is pushed to QuickBooks. The pay app must be on the invoice’s own project, live (submitted, sent, approved or paid) and not already claimed by another live invoice; the installment must be on the project’s bid’s payment term and not billed by another live invoice. An invoice bills a pay app or an installment, not both. The response carries the project’s billed figures before and after; dryRun: true returns them without saving.

id
required
integer
Idempotency-Key
string format: uuid
<= 255 characters

Idempotent retry key for mutating operations. The first request with a given key executes normally and BuildWorkPro caches the response. Replaying the same key with the same request body (method + path + JSON body, SHA-256 hashed) returns the cached response without re-executing the mutation. Replaying with a DIFFERENT body returns 409 idempotency_key_reused. The cache TTL is 24 hours; after expiry the key is treated as a new operation. Keys are tenant-scoped. Recommended: a fresh UUID v4 per logical operation.

Media type application/json
object
sourcePayAppId

Pay application this invoice bills (same project, submitted/sent/approved/paid, not claimed by another live invoice). null unlinks.

integer | null
> 0
paymentTermInstallmentId

Payment-schedule installment this invoice bills (on the project’s bid’s payment term, not billed by another live invoice). null unlinks.

integer | null
> 0
sourceBidId

The project’s bid, printed on the invoice PDF. null unlinks.

integer | null
> 0
dryRun

Validate and return the billed-figure preview without saving.

boolean
Example generated
{
"sourcePayAppId": 1,
"paymentTermInstallmentId": 1,
"sourceBidId": 1,
"dryRun": true
}

Linked

Media type application/json
object
data
required
object
invoice
required
object
id
required
integer
tenantId
required
integer
invoiceNumber
required
string
projectId
required
integer | null
contactId
required
integer | null
status
required
string
Allowed values: draft sent partial paid voided
issueDate
required
string | null format: date-time
dueDate
required
string | null format: date-time
subtotal
required
string
taxAmount
required
string
total
required
string
amountPaid
required
string
balanceDue
required
string
notesToCustomer
required
string | null
createdAt
required
string format: date-time
updatedAt
required
string format: date-time
before
required
object
sourcePayAppId
required
integer | null
paymentTermInstallmentId
required
integer | null
sourceBidId
required
integer | null
sourceType
required
string
Allowed values: bid pay_app ad_hoc
after
required
object
sourcePayAppId
required
integer | null
paymentTermInstallmentId
required
integer | null
sourceBidId
required
integer | null
sourceType
required
string
Allowed values: bid pay_app ad_hoc
changed
required
boolean
dryRun
required
boolean
billing
required
object
before
required
object
invoiced
required
number
invoicedPreTax
required
number
paid
required
number
outstanding
required
number
invoiceCount
required
integer
payAppBilled
required
number
billedTotal
required
number
billedCash
required
number
outstandingCash
required
number
retainageHeld
required
number
remaining
required
number
hasBilling
required
boolean
after
required
object
invoiced
required
number
invoicedPreTax
required
number
paid
required
number
outstanding
required
number
invoiceCount
required
integer
payAppBilled
required
number
billedTotal
required
number
billedCash
required
number
outstandingCash
required
number
retainageHeld
required
number
remaining
required
number
hasBilling
required
boolean
meta
required
object
request_id

Server-generated request identifier

string
pagination
object
cursor
required

Opaque cursor for the next page; null when no more results

string | null
has_more
required

Whether more pages are available after this one

boolean
count
required

Items in this page

integer
Example
{
"data": {
"invoice": {
"status": "draft"
},
"before": {
"sourceType": "bid"
},
"after": {
"sourceType": "bid"
}
}
}

Error

Media type application/problem+json
object
type
required

URL identifying the problem type

string format: uri
title
required

Short human-readable summary

string
status
required

HTTP status code

integer
detail

Human-readable explanation

string
request_id

Server-generated request identifier

string
errors

Validation error array (422 only)

Array<object>
object
field
required

Field path that failed validation

string
code
required

Validation error code

string
message
required

Human-readable validation message

string
Example generated
{
"type": "https://example.com",
"title": "example",
"status": 1,
"detail": "example",
"request_id": "example",
"errors": [
{
"field": "example",
"code": "example",
"message": "example"
}
]
}

Error

Media type application/problem+json
object
type
required

URL identifying the problem type

string format: uri
title
required

Short human-readable summary

string
status
required

HTTP status code

integer
detail

Human-readable explanation

string
request_id

Server-generated request identifier

string
errors

Validation error array (422 only)

Array<object>
object
field
required

Field path that failed validation

string
code
required

Validation error code

string
message
required

Human-readable validation message

string
Example generated
{
"type": "https://example.com",
"title": "example",
"status": 1,
"detail": "example",
"request_id": "example",
"errors": [
{
"field": "example",
"code": "example",
"message": "example"
}
]
}

Error

Media type application/problem+json
object
type
required

URL identifying the problem type

string format: uri
title
required

Short human-readable summary

string
status
required

HTTP status code

integer
detail

Human-readable explanation

string
request_id

Server-generated request identifier

string
errors

Validation error array (422 only)

Array<object>
object
field
required

Field path that failed validation

string
code
required

Validation error code

string
message
required

Human-readable validation message

string
Example generated
{
"type": "https://example.com",
"title": "example",
"status": 1,
"detail": "example",
"request_id": "example",
"errors": [
{
"field": "example",
"code": "example",
"message": "example"
}
]
}