Xero Invoices — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Xero Invoices (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Invoices are the core transaction entity in Xero for billing and accounts payable. For MSPs, invoices represent two primary flows: sales invoices (ACCREC) for billing managed services clients, and supplier bills (ACCPAY) for vendor costs like software licenses, hardware purchases, and ISP charges.
demand for payment, not an offer; use salesbuildr-quotes, connectwise-cpq-quotes, or pandadoc-documents.
the hosted payment rail is alternative-payments-invoicing and recording the receipt is xero-payments.
hand; use xero-reports.
qbo-invoices.agreements and time, and a distributor bills the MSP for licences; neither posts to Xero until it is entered. Use halopsa-invoices, syncro-invoices, or pax8-invoices.
| Type | Code | Description | MSP Use Case |
|---|---|---|---|
| Sales Invoice | ACCREC | Accounts Receivable - you bill a customer | Monthly managed services, project work |
| Supplier Bill | ACCPAY | Accounts Payable - a vendor bills you | Software licenses, hardware, ISP bills |
DRAFT --> SUBMITTED --> AUTHORISED --> PAID
\--> VOIDED
\--> DELETED (draft only)| Status | Description | Editable | Can Pay |
|---|---|---|---|
DRAFT | Created but not submitted | Yes | No |
SUBMITTED | Submitted for approval | Limited | No |
AUTHORISED | Approved and sent to client | No | Yes |
PAID | Fully paid | No | N/A |
VOIDED | Cancelled/voided | No | No |
DELETED | Removed (draft only) | N/A | N/A |
Xero auto-generates sequential invoice numbers (e.g., INV-0001, INV-0002) or you can set custom numbers using the InvoiceNumber field. MSPs often use prefixes like MS- for managed services or PJ- for project invoices.
An invoice needs Type, a Contact with a valid ContactID, and at least one line item. Line items need Description, and — to reach AUTHORISED — UnitAmount and AccountCode. LineAmountTypes (Exclusive, Inclusive, NoTax) determines whether UnitAmount includes tax. SubTotal, TotalTax, Total, AmountDue, AmountPaid, and AmountCredited are read-only and calculated by Xero.
See references/fields.md for the complete field reference.
Both create and update go through POST — POST /Invoices creates (or batch-creates via an Invoices array), POST /Invoices/{InvoiceID} updates. There is no PATCH and no DELETE for authorised invoices; set Status: "VOIDED" instead.
curl -s -X POST "https://api.xero.com/api.xro/2.0/Invoices" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "xero-tenant-id: ${XERO_TENANT_ID}" \
-H "Content-Type: application/json" \
-d '{
"Type": "ACCREC",
"Contact": { "ContactID": "'${CONTACT_ID}'" },
"Date": "2026-03-01T00:00:00",
"DueDate": "2026-03-31T00:00:00",
"LineAmountTypes": "Exclusive",
"Reference": "March 2026 Managed Services",
"LineItems": [
{ "Description": "Monthly Managed Services (25 endpoints)", "Quantity": 1, "UnitAmount": 2500.00, "AccountCode": "200", "TaxType": "OUTPUT" }
],
"Status": "DRAFT"
}'Filtering uses the where query parameter with URL-encoded expressions — Type=="ACCREC", AmountDue>0, Contact.ContactID==guid("..."), Date>=DateTime(2026,3,1). Add ?summarizeErrors=false to batch requests to get per-invoice errors instead of a single aggregate failure.
See references/api.md for the full request catalog (filters, bills, void, batch, credit notes) and the endpoint reference.
/Invoices/{InvoiceID}/EmailStatus=="AUTHORISED" && DueDate < today)Attach a Tracking array to each line item (Name/Option pairs like Department + Region) so P&L can be filtered by service line later.
Partial credits go through /CreditNotes with Type: "ACCRECCREDIT" rather than editing the original invoice — the invoice stays intact for audit.
Compare the set of active customer contacts against the Contact.ContactID values on ACCREC invoices in the billing period.
See references/examples.md for working JavaScript implementations of these workflows.
| Code | Message | Resolution |
|---|---|---|
| 400 | Account code is not valid | Verify AccountCode exists in chart of accounts |
| 400 | A Contact is required | Provide Contact with valid ContactID |
| 400 | At least one line item is required | Add LineItems array with entries |
| 400 | Invoice number already used | Use unique InvoiceNumber or omit for auto |
| 400 | Cannot void a paid invoice | Reverse payment first, then void |
| 401 | Unauthorized | Refresh access token |
| 404 | Invoice not found | Verify InvoiceID |
Validation failures return HTTP 200 with the error attached to the invoice object — check HasErrors on every returned invoice rather than relying on the status code:
{
"Invoices": [
{
"InvoiceID": "00000000-0000-0000-0000-000000000000",
"HasErrors": true,
"ValidationErrors": [
{ "Message": "Account code '999' is not a valid code for this document." }
]
}
]
}HasErrors: true; parse per-invoice results, especially in batches.DELETED is only available for drafts. Voiding preserves the audit trail and the invoice number.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.