Skip to content
TruTecDevelopers
Get an API key

Invoices & payments

List and read invoices, draft invoices from line items, edit them, email them to the customer, mark them sent, paid or void, or put them back to draft. Read payments.

View as Markdown

An invoice bills a job's customer. TruTec has two kinds:

payment_method What it is Through the API
check A manual invoice the customer pays by check, ACH or another way you record. Statuses draft, sent, paid, void. Read, create, edit, send, mark sent, mark paid, void, back to draft.
stripe An online invoice the customer pays by card or bank. Statuses open, paid, void, uncollectible, set only by the payment processor. Read, and create from an estimate with Request payment online.

The API never charges a card. Invoice objects never carry the customer's payment link; the one place it is returned is the response of Request payment online.

Invoices you create start as drafts. A draft is not emailed and is not posted to accounting. Use /send to email it, or /mark-sent when you deliver it another way. When the workspace is connected to QuickBooks Online or another accounting system, the invoice and its payment sync on those steps exactly as in TruTec.

Money is in dollars with two decimals. The job invoice list (GET /v1/jobs/{id}/invoices, see Job costing) returns the same rows without the contents.

The invoice object#

Field Type Description
id, job_id integer
doc_number integer or null The estimate's document number, for invoices billed from an estimate.
status, payment_method, billing_type string billing_type is full, deposit, milestone, custom, line_items or recurring.
description string First line item, or "N line items".
line_items array {description, amount}.
subtotal, discount, tax, amount number amount = subtotal − discount + tax. Each also comes in cents (amount_cents and so on).
due_date, payment_terms For example Net 30 or Due on receipt.
issued_at, paid_at, updated_at, created_at string UTC.
client_name, client_email, client_address Who is billed.
project_name, project_address, reference_number, memo
remit_to_name, remit_to_address, payment_instructions Where and how to pay.
sender_name, sender_email, created_by Who it's from.
estimate_id integer or null The estimate it bills.
quickbooks object has_invoice, has_payment, invoice_synced_at, sync_error.

Invoices#

List invoices#

GET /v1/invoices

Permission: Read jobs

Newest first. With updated_after, sorted by updated_at, oldest first.

Name Type Required Description
job_id integer No
status string No
payment_method string No check or stripe.
updated_after string No ISO 8601.
limit, offset integer No Default 50, maximum 200.
curl "https://trutec.ai/api/v1/invoices?job_id=70412" \
  -H "X-API-Key: sk_your_api_key_here"
{
  "data": [
    {
      "id": 7790,
      "job_id": 70412,
      "doc_number": null,
      "status": "draft",
      "billing_type": "line_items",
      "payment_method": "check",
      "description": "2 line items",
      "currency": "usd",
      "amount_cents": 1405050,
      "amount": 14050.5,
      "subtotal_cents": 1395050,
      "subtotal": 13950.5,
      "discount_cents": 0,
      "discount": 0.0,
      "tax_cents": 10000,
      "tax": 100.0,
      "due_date": "2026-11-26T15:02:11Z",
      "issued_at": "2026-11-11T15:02:11Z",
      "paid_at": null,
      "updated_at": "2026-11-11T15:02:11Z",
      "quickbooks": { "has_invoice": false, "has_payment": false, "invoice_synced_at": null, "sync_error": null },
      "line_items": [
        { "description": "Sealcoat, 2 coats", "amount": 12500.0 },
        { "description": "Striping", "amount": 1450.5 }
      ],
      "client_name": "Northgate Property Group",
      "client_email": "[email protected]",
      "client_address": null,
      "project_name": "Northgate Plaza reseal",
      "project_address": "1200 Commerce Dr, Austin, TX 78701",
      "reference_number": "PO-5521",
      "memo": "Thank you for your business.",
      "payment_terms": "Net 15",
      "remit_to_name": "Northgate Paving",
      "remit_to_address": "400 Industrial Way, Austin, TX 78702",
      "payment_instructions": null,
      "sender_name": "Northgate Paving",
      "sender_email": "[email protected]",
      "estimate_id": null,
      "created_by": { "id": 12, "name": "Office Manager" },
      "created_at": "2026-11-11T15:02:11Z"
    }
  ],
  "pagination": { "total": 1, "limit": 50, "offset": 0 }
}

Get an invoice#

GET /v1/invoices/{id}

Permission: Read jobs

Create a draft invoice#

POST /v1/invoices

Permission: Write jobs

Creates a manual (check) invoice on a job as a draft. The customer name and email default from the job's bill-to, then its company and contact. The remit-to address defaults to the last one the workspace used.

Name Type Required Description
job_id integer Yes
line_items array Yes [{"description": "...", "amount": 1250.00}], amounts in dollars, above 0.
client_name, client_email, client_address string No Override the job's billing contact.
billing_type string No line_items (default), full, deposit, milestone or custom.
due_days integer No Days until due. Default 30; 0 is due on receipt.
discount, tax number No Dollars. The discount can't exceed the subtotal.
memo, reference_number, project_name, project_address string No
remit_to_name, remit_to_address, payment_instructions string No A remit-to address is required if the workspace has none on file.
estimate_id integer No The job's estimate this invoice bills.
curl -X POST "https://trutec.ai/api/v1/invoices" \
  -H "X-API-Key: sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "job_id": 70412,
    "line_items": [
      { "description": "Sealcoat, 2 coats", "amount": 12500 },
      { "description": "Striping", "amount": 1450.50 }
    ],
    "tax": 100,
    "due_days": 15,
    "reference_number": "PO-5521"
  }'

Returns 201 with the invoice.

Errors: 400 for missing or invalid line items, a missing remit-to address, or a total of zero. 404 when the job or estimate is not in your workspace.

Update an invoice#

PATCH /v1/invoices/{id}

Permission: Write jobs

Changes the fields you send (the same fields as Create, except job_id and estimate_id). line_items replaces the whole list. The due date stays anchored to the issue date. If the invoice is already in QuickBooks Online, the edit is pushed there too. Online invoices (stripe) return 409; invoices imported from another system keep their original figures (409).

Send an invoice#

POST /v1/invoices/{id}/send

Permission: Write jobs

This emails the customer (client_email) the invoice with a link to view it, from the workspace's designated invoice sender, or else from the key creator's connected mailbox. A draft becomes sent and, on first send, is created in the connected accounting system. You can send again to resend. Returns 200 with emailed: true.

Errors: 422 when the invoice has no client_email. 409 for a void or online invoice. 502 if the email could not be delivered.

Mark sent, mark paid, or void#

POST /v1/invoices/{id}/mark-sent

POST /v1/invoices/{id}/mark-paid

POST /v1/invoices/{id}/void

Permission: Write jobs

Nothing is emailed. mark-sent is for invoices you delivered yourself (it also moves a paid invoice back to unpaid). mark-paid records the payment today and posts it to the connected accounting system. void voids the invoice there too. Online invoices return 409: their status follows the payment processor.

Request payment online#

POST /v1/estimates/{id}/request-payment

Permission: Write jobs (the key's user needs pricing access)

Bills an estimate with an online invoice, exactly like Create invoice with the Online (card / bank) method on the estimate's Billing tab. The amount, bill-to, due date, accounting sync and double-billing guard are TruTec's own.

Warning

This emails the customer. The workspace's connected payments account emails them a page to pay by card or bank right away. Confirm the amount and the customer before calling it.

Name Type Description
kind string full (the contract, the default), deposit (the proposal's deposit percent), progress (work done so far minus what's already billed) or itemized (one line per item).
due_days integer Days until due. Default: the proposal's payment terms.
memo, reference_number string reference_number is the customer's PO number.
client_name, client_email string Who is billed and where the invoice is emailed. Default: the job's bill-to, else the proposal's customer.
confirm_duplicate boolean Bill anyway after a 409 double-billing refusal.

Needs online payments connected in TruTec (Settings › Payments; 409 Online payments not set up otherwise) and a prepared proposal (409 No proposal yet; see Proposals). The same invoice again within 10 minutes, or a full-contract invoice that would bill more than the contract, is refused with 409 and code duplicate_invoice or over_contract unless you send confirm_duplicate: true.

curl -X POST "https://trutec.ai/api/v1/estimates/9840/request-payment" \
  -H "X-API-Key: sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"kind": "deposit"}'
{
  "data": {
    "invoice": {"id": 9120, "job_id": 70412, "status": "open", "payment_method": "stripe", "billing_type": "deposit", "amount": 12125.0, "...": "..."},
    "payment_url": "https://invoice.stripe.com/i/acct_example/test_example",
    "emailed": true,
    "message": "Invoice created and submitted to Stripe for email delivery."
  }
}

Returns 201. emailed is false when the invoice was made but the payments account couldn't confirm the email: share payment_url yourself rather than requesting again. The invoice's status follows the payment processor (webhook payment_received when paid). Mailed-check invoices: Create a draft invoice.

Payments#

List payments#

GET /v1/payments

Permission: Read jobs

One row per paid invoice, most recent first. TruTec records a payment when an invoice is marked paid, or when the customer pays an online invoice. Partial payments are not tracked.

Name Type Required Description
job_id integer No
paid_after string No ISO 8601.
limit, offset integer No
{
  "data": [
    {
      "invoice_id": 7781,
      "job_id": 70412,
      "doc_number": 1412,
      "amount": 14550.0,
      "currency": "usd",
      "paid_at": "2026-10-18T19:02:13Z",
      "payment_method": "check",
      "client_name": "Northgate Property Group",
      "quickbooks": { "has_payment": true, "payment_synced_at": "2026-10-18T19:02:40Z" }
    }
  ],
  "pagination": { "total": 1, "limit": 50, "offset": 0 }
}

Back to draft#

Move an invoice back to draft#

POST /v1/invoices/{id}/mark-draft

Permission: Write jobs

The same as choosing Draft in the invoice's status menu in TruTec. A void invoice is no longer void, and a paid invoice loses its payment date (it drops out of GET /v1/payments). Nothing is emailed. Use it to undo a mark-sent, mark-paid or void made by mistake, then edit the invoice and send it again.

If the invoice is already in the connected accounting system, that copy stays there: marking the invoice sent again pushes your edits to it (a copy that was voided there is replaced with a new one). A payment already posted there is not removed; remove it in the accounting system.

curl -X POST "https://trutec.ai/api/v1/invoices/7790/mark-draft" \
  -H "X-API-Key: sk_your_api_key_here"

Returns 200 with the invoice, status draft.

Errors: 400 when the invoice is linked to another invoicing system and was already sent or paid. 409 for an online invoice. 404 when the invoice is not in your workspace.

Deleting invoices#

Invoices can't be deleted, in TruTec or through the API. Void one instead (POST /v1/invoices/{id}/void): it stays on the job for your records and is voided in the connected accounting system too.