Invoices
Create and manage customer invoices
Overview
Invoices track billing for services rendered. They can contain multiple line items, apply taxes, and integrate with Stripe and QuickBooks for billing and accounting. Invoices support various payment statuses and can be created as local invoices or synced with external providers.
List Invoices (Cursor-Based)
Retrieve a cursor-based paginated list of invoices with filtering and sorting. Requires read:invoice permission.
query InfiniteInvoices(
$first: Int!
$after: String
$selector: InvoicesSelector
$sort: [InvoicesSort!]
) {
infiniteInvoices(
first: $first
after: $after
selector: $selector
sort: $sort
) {
edges {
node {
id
invoiceNumber
status
type
subtotal
taxes
total
amountPaid
issueDate
dueDate
customer {
id
firstName
lastName
}
lines {
id
description
quantity
price
type
}
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
}
}
# Variables
{
"first": 20,
"selector": {
"filters": {
"status": { "in": ["OPEN", "PAST_DUE"] },
"dueDate": { "lte": "2024-02-01T00:00:00Z" }
},
"search": "Smith"
},
"sort": [{ "field": "dueDate", "direction": "ASC" }]
}Response:
{
"data": {
"infiniteInvoices": {
"edges": [
{
"node": {
"id": "inv_001",
"invoiceNumber": "INV-2024-0001",
"status": "OPEN",
"type": "STRIPE",
"subtotal": 137.61,
"taxes": 12.39,
"total": 150.00,
"amountPaid": 0,
"issueDate": "2024-01-15T00:00:00Z",
"dueDate": "2024-01-31T00:00:00Z",
"customer": {
"id": "cust_456",
"firstName": "John",
"lastName": "Smith"
},
"lines": [
{
"id": "li_001",
"description": "Weekly Pool Cleaning - January",
"quantity": 2,
"price": 75.00,
"type": "SERVICE_TYPE"
}
]
},
"cursor": "eyJpZCI6Imludl8wMDEifQ=="
}
],
"pageInfo": {
"hasNextPage": true,
"endCursor": "eyJpZCI6Imludl8wMDEifQ=="
}
}
}
}List Invoices (Offset-Based)
Retrieve an offset-based paginated list of invoices. Maximum 100 per page. Requires read:invoice permission.
query PaginatedInvoices(
$limit: Int!
$page: Int!
$selector: InvoicesSelector
$sort: [InvoicesSort!]
) {
paginatedInvoices(
limit: $limit
page: $page
selector: $selector
sort: $sort
) {
items {
id
invoiceNumber
status
total
amountPaid
issueDate
dueDate
customer {
id
firstName
lastName
}
}
totalCount
page
limit
}
}
# Variables
{
"limit": 25,
"page": 1,
"selector": {
"filters": {
"status": { "equals": "PAID" },
"issueDate": { "gte": "2024-01-01T00:00:00Z" }
}
},
"sort": [{ "field": "issueDate", "direction": "DESC" }]
}Response:
{
"data": {
"paginatedInvoices": {
"items": [
{
"id": "inv_003",
"invoiceNumber": "INV-2024-0003",
"status": "PAID",
"total": 200.00,
"amountPaid": 200.00,
"issueDate": "2024-01-20T00:00:00Z",
"dueDate": "2024-02-03T00:00:00Z"
}
],
"totalCount": 48,
"page": 1,
"limit": 25
}
}
}Preview Invoice
Preview an invoice before creating it. Requires read:invoice permission.
query PreviewInvoice($input: PreviewInvoiceInput!) {
previewInvoice(input: $input) {
subtotal
taxes
total
lines {
description
price
quantity
type
}
}
}
# Variables
{
"input": {
"customerId": "cust_456",
"serviceIds": ["svc_001", "svc_002"]
}
}Response:
{
"data": {
"previewInvoice": {
"subtotal": 250.00,
"taxes": 22.50,
"total": 272.50,
"lines": [
{
"description": "Weekly Pool Cleaning",
"price": 150.00,
"quantity": 1,
"type": "SERVICE_TYPE"
},
{
"description": "Filter Replacement",
"price": 100.00,
"quantity": 1,
"type": "INVENTORY_ITEM"
}
]
}
}
}Create Invoice
Create invoices for services. Returns an array of invoices (multiple if separateInvoicePerService is true). Requires write:invoice permission.
mutation CreateInvoice($options: CreateInvoiceOptions!) {
createInvoice(options: $options) {
id
invoiceNumber
status
type
total
issueDate
dueDate
createdAt
}
}
# Variables
{
"options": {
"issueDate": "2024-01-20T00:00:00Z",
"daysUntilDue": 15,
"separateInvoicePerService": false,
"includeSurcharge": false,
"allowOnlineAchPayment": true,
"allowOnlineCreditCardPayment": true,
"sendInvoices": true,
"provider": "STRIPE",
"messageOnInvoice": "Thank you for your business!",
"customLines": [
{
"description": "Pool Repair - Filter Replacement",
"quantity": 1,
"price": 250.00
}
]
}
}Response:
{
"data": {
"createInvoice": [
{
"id": "inv_002",
"invoiceNumber": "INV-2024-0002",
"status": "OPEN",
"type": "STRIPE",
"total": 271.25,
"issueDate": "2024-01-20T00:00:00Z",
"dueDate": "2024-02-04T00:00:00Z",
"createdAt": "2024-01-20T09:00:00Z"
}
]
}
}Create Local Invoice
Create a local invoice for a specific customer with custom line items. Requires non-empty custom lines. Requires write:invoice permission.
mutation CreateLocalInvoice($customerId: ID!, $input: CreateInvoiceOptions!) {
createLocalInvoice(customerId: $customerId, input: $input) {
id
invoiceNumber
status
type
total
issueDate
dueDate
lines {
id
description
price
quantity
type
}
}
}
# Variables
{
"customerId": "cust_456",
"input": {
"issueDate": "2024-01-20T00:00:00Z",
"daysUntilDue": 30,
"separateInvoicePerService": false,
"includeSurcharge": false,
"allowOnlineAchPayment": false,
"allowOnlineCreditCardPayment": false,
"sendInvoices": false,
"customLines": [
{
"description": "Emergency Pool Pump Repair",
"quantity": 1,
"price": 350.00
},
{
"description": "Replacement Parts",
"quantity": 3,
"price": 45.00
}
]
}
}Response:
{
"data": {
"createLocalInvoice": {
"id": "inv_005",
"invoiceNumber": "INV-2024-0005",
"status": "DRAFT",
"type": "LOCAL",
"total": 485.00,
"issueDate": "2024-01-20T00:00:00Z",
"dueDate": "2024-02-19T00:00:00Z",
"lines": [
{
"id": "li_010",
"description": "Emergency Pool Pump Repair",
"price": 350.00,
"quantity": 1,
"type": "SERVICE_CALL_FEE"
},
{
"id": "li_011",
"description": "Replacement Parts",
"price": 45.00,
"quantity": 3,
"type": "INVENTORY_ITEM"
}
]
}
}
}Update Invoice
Update an existing invoice. Requires write:invoice permission.
mutation UpdateInvoice($id: ID!, $input: UpdateInvoiceInput!) {
updateInvoice(id: $id, input: $input) {
id
invoiceNumber
status
total
dueDate
notes
}
}
# Variables
{
"id": "inv_001",
"input": {
"notes": "Updated payment terms",
"messageOnInvoice": "Payment due upon receipt"
}
}Response:
{
"data": {
"updateInvoice": {
"id": "inv_001",
"invoiceNumber": "INV-2024-0001",
"status": "OPEN",
"total": 150.00,
"dueDate": "2024-01-31T00:00:00Z",
"notes": "Updated payment terms"
}
}
}Delete Invoice
Delete an invoice. Requires delete:invoice permission.
mutation DeleteInvoice($id: ID!) {
deleteInvoice(id: $id)
}
# Variables
{
"id": "inv_001"
}Response:
{
"data": {
"deleteInvoice": true
}
}Pay Invoice
Record a payment against an invoice. Requires write:invoice permission.
mutation PayInvoice($id: ID!, $paymentSourceId: String!, $provider: InvoiceType!) {
payInvoice(id: $id, paymentSourceId: $paymentSourceId, provider: $provider) {
id
status
amountPaid
total
paidDate
}
}
# Variables
{
"id": "inv_001",
"paymentSourceId": "pm_abc123",
"provider": "STRIPE"
}Response:
{
"data": {
"payInvoice": {
"id": "inv_001",
"status": "PAID",
"amountPaid": 150.00,
"total": 150.00,
"paidDate": "2024-01-20T15:00:00Z"
}
}
}Resend Invoice
Resend an invoice notification to the customer. Requires write:invoice permission.
mutation ResendInvoice($id: ID!, $sendService: InvoiceService) {
resendInvoice(id: $id, sendService: $sendService) {
id
invoiceNumber
status
}
}
# Variables
{
"id": "inv_001",
"sendService": "EMAIL"
}Response:
{
"data": {
"resendInvoice": {
"id": "inv_001",
"invoiceNumber": "INV-2024-0001",
"status": "OPEN"
}
}
}Bulk & Export Operations
Creating, updating, or exporting many invoices at once is handled asynchronously through the Bulk Operations API. These jobs run in the background and report progress you can poll. See the Bulk Operations guide for the full workflow.
Filtering and Sorting
Both infiniteInvoices and paginatedInvoices accept an InvoicesSelector with the following filter options:
InvoiceFilter fields
id- IdFiltercustomerId- IdFilterstatus- InvoiceStatusFilter (equals, in, notIn)type- InvoiceTypeEnum (STRIPE, QUICKBOOKS, LOCAL)total- NumberFilterissueDate- DateTimeFilterdueDate- DateTimeFiltercustomerTags- IdFilter
Sortable fields
idinvoiceNumberstatustotalissueDatedueDatecustomer___firstNamecustomer___lastName
The selector also supports a search field (max 600 characters) for free-text search across invoices.
Invoice Field Reference
| Field | Type | Description |
|---|---|---|
id | ID! | Unique identifier |
invoiceNumber | String(nullable) | Invoice number |
customerId | ID! | Customer ID |
customer | Customer! | Customer being billed |
status | InvoiceStatusEnum! | Status (DRAFT, OPEN, PAID, PAST_DUE, EXPORTED, QUICKBOOKS, STRIPE) |
type | InvoiceTypeEnum! | Invoice provider type (STRIPE, QUICKBOOKS, LOCAL) |
subtotal | Float! | Subtotal before tax |
taxes | Float! | Tax amount |
total | Float! | Total amount due |
amountPaid | Float! | Amount paid |
issueDate | DateTime! | Date invoice was issued |
dueDate | DateTime(nullable) | Payment due date |
paidDate | DateTime(nullable) | When invoice was paid |
notes | String(nullable) | Invoice notes |
stripeInvoiceId | String(nullable) | Stripe invoice ID |
quickbooksId | String(nullable) | QuickBooks invoice ID |
editInvoiceUrl | String(nullable) | URL to edit the invoice in the provider |
invoicePdf | String(nullable) | URL to the invoice PDF |
hostedInvoiceUrl | String(nullable) | URL to the hosted invoice page |
canPay | Boolean(nullable) | Whether the invoice can be paid |
canChangeStatus | Boolean(nullable) | Whether the invoice status can be changed |
surchargeEnabled | Boolean! | Whether surcharge is enabled |
surchargePercent | Float(nullable) | Surcharge percentage |
messageOnInvoice | String(nullable) | Custom message displayed on the invoice |
messageOnStatement | String(nullable) | Custom message displayed on statements |
createdAt | DateTime! | Creation timestamp |
lines | [InvoiceLine!](nullable) | Invoice line items |
InvoiceLine Field Reference
| Field | Type | Description |
|---|---|---|
id | ID! | Unique identifier |
lineDate | DateTime! | Date for this line item |
description | String! | Line item description |
detail | String(nullable) | Additional detail |
price | Number! | Unit price |
quantity | Number! | Quantity |
type | String! | Line type (SERVICE_TYPE, SERVICE_CALL_FEE, INVENTORY_ITEM) |
isTaxable | Boolean(nullable) | Whether this line is taxable |
metadata | InvoiceLineMetadata(nullable) | Additional metadata for this line |