Invoices
Create and manage invoices, generate them from approved time entries, and share client-facing links.
All endpoints require authentication with an API key via Authorization: Bearer anch_... — see Authentication. A :write scope implicitly includes its :read scope.
Quick example
curl "https://your-domain.com/api/invoices?status=sent" \
-H "Authorization: Bearer anch_your_api_key"Endpoints
/api/invoices/api/invoices/api/invoices/{id}/api/invoices/{id}/api/invoices/{id}/api/invoices/from-time-entries/api/invoices/{id}/send/api/invoices/{id}/client-link/api/invoices/{id}/payment-linkGET/api/invoices
Unlike the other list endpoints, this returns { data } without a meta pagination object.
Query parameters
| Field | Type | Description |
|---|---|---|
dealId | string | Filter to invoices for a specific deal |
status | string | Filter by status (see enumeration below) |
limit | integer | Page size (default: 50, max: 100) |
offset | integer | Pagination offset (default: 0) |
Response (200)
{
"data": [ { "id": "inv_...", "invoiceNumber": "INV-0042", "status": "sent", ... } ]
}POST/api/invoices
All fields are optional — an empty body creates a draft with an auto-generated invoice number.
Body fields
| Field | Type | Description |
|---|---|---|
dealId | string | Associated deal |
invoiceNumber | string | Auto-generated when omitted |
status | string | Invoice status (default: draft) |
issuedDate | integer | string | Issue date — Unix ms or ISO string |
dueDate | integer | string | Due date |
paidDate | integer | string | Paid date |
paymentMethod | string | How the invoice was paid |
paymentReference | string | External payment reference |
subtotalCents | integer | Subtotal in cents (default: 0) |
taxRate | number | Tax rate percentage (default: 0) |
taxLabel | string | Label shown for tax (default: "Tax") |
taxCents | integer | Tax amount in cents (default: 0) |
totalCents | integer | Total in cents (default: 0) |
currency | string | ISO currency code (default: USD) |
notes | string | Notes shown on the invoice |
paymentTerms | string | Payment terms text |
showRateBreakdown | boolean | Show hourly rate breakdown (default: false) |
includeTimesheet | boolean | Attach timesheet detail (default: false) |
Response (201)
{ "id": "inv_V1StGXR8Z5jdHi6B", "invoiceNumber": "INV-0042" }GET/api/invoices/{id}
Response (200)
{
"data": {
"id": "inv_V1StGXR8Z5jdHi6B",
"organizationId": "org_4f90...",
"invoiceNumber": "INV-0042",
"dealId": "dl_...",
"status": "sent",
"issuedDate": 1736899200000,
"dueDate": 1739577600000,
"subtotalCents": 240000,
"taxRate": 8.25,
"taxCents": 19800,
"totalCents": 259800,
"currency": "USD",
"createdAt": 1736899200000,
"updatedAt": 1736899200000
}
}PATCH/api/invoices/{id}
PUT is also accepted. Marking an invoice paid can automatically advance the linked deal's stage; when that happens the response includes stageAdvanced.
Body fields
| Field | Type | Description |
|---|---|---|
dealId | string | Associated deal |
invoiceNumber | string | Auto-generated when omitted |
status | string | Invoice status (default: draft) |
issuedDate | integer | string | Issue date — Unix ms or ISO string |
dueDate | integer | string | Due date |
paidDate | integer | string | Paid date |
paymentMethod | string | How the invoice was paid |
paymentReference | string | External payment reference |
subtotalCents | integer | Subtotal in cents (default: 0) |
taxRate | number | Tax rate percentage (default: 0) |
taxLabel | string | Label shown for tax (default: "Tax") |
taxCents | integer | Tax amount in cents (default: 0) |
totalCents | integer | Total in cents (default: 0) |
currency | string | ISO currency code (default: USD) |
notes | string | Notes shown on the invoice |
paymentTerms | string | Payment terms text |
showRateBreakdown | boolean | Show hourly rate breakdown (default: false) |
includeTimesheet | boolean | Attach timesheet detail (default: false) |
Response (200)
{ "ok": true, "stageAdvanced": "paid_complete" }DELETE/api/invoices/{id}
Permanent (hard) delete. With session auth this requires a manager or admin role.
Response (200)
{ "ok": true }POST/api/invoices/from-time-entries
Builds an invoice from a set of time entries on a deal, grouping line items by task, deliverable, or a single line.
Body fields
| Field | Type | Description |
|---|---|---|
dealIdrequired | string | Deal the entries belong to |
timeEntryIdsrequired | string[] | Time entries to include |
groupBy | string | task, deliverable, or all |
notes | string | Invoice notes |
paymentTerms | string | Payment terms text |
dueDate | integer | string | Due date |
showRateBreakdown | boolean | Show hourly rate breakdown |
includeTimesheet | boolean | Attach timesheet detail |
taxRateId | string | Apply a saved tax rate |
Response (201)
{ "id": "inv_...", "invoiceNumber": "INV-0043" }POST/api/invoices/{id}/send
Body fields
| Field | Type | Description |
|---|---|---|
torequired | string | Recipient email address |
message | string | Custom message included in the email |
Response (200)
{ "ok": true }GET on the same path reports whether outbound email is configured for your organization.
POST/api/invoices/{id}/client-link
Generates a public, tokenized link where the client can view the invoice without signing in. GET retrieves the existing link.
Response (200)
{ "url": "https://your-domain.com/view/invoice/<token>" }POST/api/invoices/{id}/payment-link
Generates a Stripe payment link for the invoice. GET retrieves the existing link.
Response (200)
{ "url": "https://buy.stripe.com/..." }Enumerations
Invoice statuses
draftsentpaidoverduecancelled
Notes
- Monetary values are integers in cents.
- GET /api/invoices/public/{token} serves the client-facing invoice view and requires no authentication.