Download OpenAPI specification:
RESTful API for managing accounts receivable data in ARPilot. Authenticate with API keys (Bearer token). Available on Pro and Enterprise tiers.
Create an invoice manually or from line items. Either amount (legacy single-line) or line_items[] (with optional tax_amount / discount_amount) must produce a positive total. If both are provided, line-items math must match amount within $0.01.
invoice_number is optional — if omitted, the server generates one in the format {prefix}-{YYYY}-{NNNN} (prefix defaults to INV, configurable per tenant; sequence resets each calendar year).
After creation, the invoice status is automatically recalculated from its financial fields (amount, amount_due, external_payment_amount). For example, if amount_due is 0, status will be auto-corrected to 'paid' regardless of the status provided. Terminal statuses ('cancelled', 'draft') are respected and not auto-corrected.
source_type is set to api on every invoice created through this endpoint so the platform can distinguish API-originated invoices from QuickBooks imports for future two-way sync.
| invoice_number | string Optional. Auto-generated as {prefix}-{YYYY}-{NNNN} if omitted. |
| customer_id required | string <uuid> UUID of an existing customer. Customer must belong to your account. |
| customer_name | string Overrides the customer's company_name on this invoice. Auto-populated from customer if omitted. |
| customer_address | string |
| amount | number Required if line_items is omitted. If both are present, must equal sum(line_items) + tax_amount - discount_amount within $0.01. |
| amount_due | number Defaults to amount if omitted. If less than amount, the difference is stored as external_payment_amount. |
Array of objects Optional. When provided, the server derives | |
| tax_amount | number >= 0 Default: 0 Single tax line on the whole invoice. US-only, no per-line tax. |
| tax_rate | number [ 0 .. 1 ] Display-only effective tax rate (e.g. 0.0875 for 8.75%). The source of truth is tax_amount. |
| discount_amount | number >= 0 Default: 0 |
| currency | string Default: "USD" Value: "USD" |
| issue_date | string <date> Defaults to today if omitted |
| due_date required | string <date> |
| status | string Default: "pending" Enum: "draft" "pending" "overdue" "partial" "paid" "in_payment_plan" "in_dispute" "cancelled" |
| notes | string |
| generate_pdf | boolean Default: false Optional. When true, ARPilot renders a branded invoice PDF on create using the tenant's |
{- "invoice_number": "string",
- "customer_id": "160c0c4b-9966-4dc1-a916-8407eb10d74e",
- "customer_name": "string",
- "customer_address": "string",
- "amount": 0,
- "amount_due": 0,
- "line_items": [
- {
- "description": "string",
- "quantity": 1,
- "unit_price": 0,
- "line_amount": 0
}
], - "tax_amount": 0,
- "tax_rate": 1,
- "discount_amount": 0,
- "currency": "USD",
- "issue_date": "2019-08-24",
- "due_date": "2019-08-24",
- "status": "draft",
- "notes": "string",
- "generate_pdf": false
}When financial fields (amount, amount_due, external_payment_amount, status) are modified, the invoice balance and status are automatically recalculated. Cross-field validation ensures amount_due cannot exceed amount and external_payment_amount cannot exceed amount. Terminal statuses ('cancelled', 'draft') bypass auto-recalculation and are applied directly.
| id required | string <uuid> |
| customer_name | string |
| customer_address | string |
| amount | number Must be positive |
| amount_due | number Must be non-negative and cannot exceed amount |
| external_payment_amount | number Must be non-negative and cannot exceed amount |
| issue_date | string <date> |
| due_date | string <date> |
| status | string Enum: "draft" "pending" "overdue" "partial" "paid" "in_payment_plan" "in_dispute" "cancelled" |
| notes | string |
{- "customer_name": "string",
- "customer_address": "string",
- "amount": 0,
- "amount_due": 0,
- "external_payment_amount": 0,
- "issue_date": "2019-08-24",
- "due_date": "2019-08-24",
- "status": "draft",
- "notes": "string"
}Four actions selectable via ?action=:
upload_pdf — attach a caller-supplied base64-encoded PDF (sets pdf_source: 'user_upload').delete_pdf — remove the current PDF and clear pdf_source.generate_pdf — render a branded PDF on the server using the tenant's user_branding (sets pdf_source: 'arpilot_generated'). Returns 409 if the invoice already has a user_upload or quickbooks PDF — delete it first. Regenerating over an existing arpilot_generated PDF is idempotent.send — send the invoice to its customer using a chosen email template, immediately or scheduled. Requires template_id (an email template with template_stage='initial_send' — discover via GET /v1/templates). Optional scheduled_date (ISO-8601; omit for send-now). Optional cc_self. Flips invoice status draft → pending idempotently. No source_type restriction — works on QuickBooks-imported invoices too.Uploading replaces any existing PDF.
| id required | string <uuid> |
| action required | string Enum: "upload_pdf" "delete_pdf" "generate_pdf" "send" upload_pdf — attach a PDF; delete_pdf — remove the current attachment; generate_pdf — render a branded PDF server-side; send — dispatch the invoice to the customer using a template |
| pdf_base64 | string Base64-encoded PDF file content. Required when action=upload_pdf. Ignored for delete_pdf, generate_pdf, and send. |
| template_id | string <uuid> Required when action=send. UUID of an email template with |
| scheduled_date | string <date-time> Used by action=send only. ISO-8601 timestamp. Omit (or pass null) to send immediately; past timestamps also send immediately. Future timestamps queue the send until that moment. |
| cc_self | boolean Used by action=send only. Default false. When true, CCs the tenant account email on the outgoing message. |
{- "pdf_base64": "string",
- "template_id": "c6d67e98-83ea-49f0-8812-e4abae2b68bc",
- "scheduled_date": "2019-08-24T14:15:22Z",
- "cc_self": true
}Returns a paginated list of email templates eligible to use with POST /v1/invoices/{id}?action=send. Filters: type='email' AND template_stage='initial_send'. Dunning / collections templates are excluded — they're not valid first-touch sends. Includes templates owned by the key holder (user_id matches) plus system templates (user_id IS NULL). Read-only by design — template authoring lives in the ARPilot UI. Reuses the invoices API key scope; no separate scope to rotate.
| page | integer Default: 1 |
| per_page | integer <= 100 Default: 25 |
| company_name required | string |
| customer_id | string Your internal customer ID. Auto-generated if omitted. |
| address | string |
required | Array of objects non-empty At least one contact required. Each contact must have contact_name and email. |
| tags | Array of strings Tag names (auto-created if new) |
{- "company_name": "string",
- "customer_id": "string",
- "address": "string",
- "contacts": [
- {
- "contact_name": "string",
- "email": "user@example.com",
- "phone": "string",
- "phone_type": "string",
- "is_primary": true,
- "escalation_level": 0,
- "title": "string"
}
], - "tags": [
- "string"
]
}Update customer fields, tags, and/or contacts. Contacts use upsert semantics: include 'id' to update an existing contact, omit 'id' to create a new one. Contacts not mentioned in the array are left untouched. When contact email, name, or phone changes, pending scheduled communications are automatically refreshed.
| id required | string <uuid> |
| company_name | string |
| address | string |
| timezone | string IANA timezone (e.g. America/New_York) |
| tags | Array of strings Replace all tags (UUIDs or names) |
Array of objects Upsert contacts: include 'id' to update existing, omit to create new. Non-mentioned contacts are untouched. | |
| delete_contact_ids | Array of strings <uuid> [ items <uuid > ] UUIDs of contacts to delete. Cannot delete the last contact. |
{- "company_name": "string",
- "address": "string",
- "timezone": "string",
- "tags": [
- "string"
], - "contacts": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "contact_name": "string",
- "email": "user@example.com",
- "phone": "string",
- "phone_type": "string",
- "phone_secondary": "string",
- "phone_type_secondary": "string",
- "is_primary": true,
- "escalation_level": 0,
- "title": "string",
- "notes": "string"
}
], - "delete_contact_ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}| amount required | number |
| payment_date required | string <date> |
| payment_method | string e.g. ach, check, wire, other |
| payer_name | string |
| payer_reference | string |
| external_payment_id | string Your system's payment ID (auto-generated if omitted) |
| notes | string |
{- "amount": 0,
- "payment_date": "2019-08-24",
- "payment_method": "string",
- "payer_name": "string",
- "payer_reference": "string",
- "external_payment_id": "string",
- "notes": "string"
}| id required | string <uuid> |
| invoice_id | string <uuid> Set to a valid UUID to match; null to unmatch |
| payer_name | string |
| payer_reference | string |
| reviewed | boolean |
| notes | string |
{- "invoice_id": "f4c4edb8-11e0-4b33-bcc1-482dc59ebb32",
- "payer_name": "string",
- "payer_reference": "string",
- "reviewed": true,
- "notes": "string"
}| id required | string <uuid> |
| customer_ids required | Array of strings <uuid> [ items <uuid > ] |
{- "customer_ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}| id required | string <uuid> |
| customer_ids required | Array of strings <uuid> [ items <uuid > ] |
{- "customer_ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}| customer_ids required | Array of strings <uuid> [ items <uuid > ] |
| add_tag_ids | Array of strings <uuid> [ items <uuid > ] |
| remove_tag_ids | Array of strings <uuid> [ items <uuid > ] |
{- "customer_ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "add_tag_ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "remove_tag_ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}Create a new contact for a customer. Requires customer_id, contact_name, and email. When created, if email/phone triggers downstream changes, scheduled communications are updated automatically.
| customer_id required | string <uuid> |
| contact_name required | string |
| email required | string <email> |
| phone | string or null |
| phone_type | string or null Enum: "mobile" "home" "work" "office" "fax" "other" |
| phone_secondary | string or null |
| phone_type_secondary | string or null Enum: "mobile" "home" "work" "office" "fax" "other" |
| is_primary | boolean Default: false |
| escalation_level | integer Default: 0 |
| title | string or null |
| notes | string or null |
{- "customer_id": "160c0c4b-9966-4dc1-a916-8407eb10d74e",
- "contact_name": "string",
- "email": "user@example.com",
- "phone": "string",
- "phone_type": "mobile",
- "phone_secondary": "string",
- "phone_type_secondary": "mobile",
- "is_primary": false,
- "escalation_level": 0,
- "title": "string",
- "notes": "string"
}Update contact fields. Only include fields you want to change. Changes to email, name, or phone automatically refresh pending scheduled communications.
| id required | string <uuid> |
| contact_name | string |
string <email> | |
| phone | string or null |
| phone_type | string or null Enum: "mobile" "home" "work" "office" "fax" "other" |
| phone_secondary | string or null |
| phone_type_secondary | string or null Enum: "mobile" "home" "work" "office" "fax" "other" |
| is_primary | boolean |
| escalation_level | integer |
| title | string or null |
| notes | string or null |
{- "contact_name": "string",
- "email": "user@example.com",
- "phone": "string",
- "phone_type": "mobile",
- "phone_secondary": "string",
- "phone_type_secondary": "mobile",
- "is_primary": true,
- "escalation_level": 0,
- "title": "string",
- "notes": "string"
}Register a new HTTPS endpoint to receive events. The signing secret is returned only in this response and cannot be retrieved again.
| url required | string Destination URL (must be https://) |
| events | Array of strings Items Enum: "*" "reconciliation.record_created" "reconciliation.record_updated" "invoice.created" "invoice.updated" "payment.created" "payment.matched" "customer.created" "customer.updated" "dispute.created" "dispute.resolved" "payment_plan.enrolled" "payment_plan.completed" "webhook.test" Event types to subscribe to. Use ["*"] for all events. |
| description | string or null |
{- "url": "string",
- "events": [
- "*"
], - "description": "string"
}| id required | string <uuid> |
| url | string |
| events | Array of strings Items Enum: "*" "reconciliation.record_created" "reconciliation.record_updated" "invoice.created" "invoice.updated" "payment.created" "payment.matched" "customer.created" "customer.updated" "dispute.created" "dispute.resolved" "payment_plan.enrolled" "payment_plan.completed" "webhook.test" |
| description | string or null |
| is_active | boolean |
{- "url": "string",
- "events": [
- "*"
], - "description": "string",
- "is_active": true
}| action required | string Enum: "mark_synced" "mark_failed" Action to perform on the changes |
| change_ids required | Array of strings <uuid> [ items <uuid > ] UUIDs of accounting changes to update |
| error_message | string Error description (only for mark_failed) |
{- "action": "mark_synced",
- "change_ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "error_message": "string"
}