Xero.Accounting.Invoices (Xero v1.0.0)

Copy Markdown View Source

Xero Accounting API – Invoices.

Types: ACCREC (sales invoices to customers) | ACCPAY (bills from suppliers)

Status Flow

DRAFT  SUBMITTED  AUTHORISED  PAID
                         
                      VOIDED

Key Xero Rules

  • Multiple-invoice GET returns contact summary only (no line items). Use page: parameter to get full line items in bulk.
  • Maximum 50 invoices per PUT (counts as 1 API call).
  • summary_only: true skips computation-heavy fields for fast responses.
  • if_modified_since: enables efficient incremental sync.
  • Requests requiring processing of >100k invoices are rejected (HTTP 400). Use filters, paging, and summary_only to reduce working set size.

Examples

# List AUTHORISED invoices (page 1, with full line items)
{:ok, result} = Xero.Accounting.Invoices.list(token, tenant_id,
  statuses: ["AUTHORISED"], page: 1)

# Incremental sync: only changed since last run
{:ok, result} = Xero.Accounting.Invoices.list(token, tenant_id,
  if_modified_since: last_sync_datetime)

# Get a single invoice (full line items always included)
{:ok, %{"Invoices" => [inv]}} = Xero.Accounting.Invoices.get(token, tenant_id, invoice_id)

# Get as PDF
{:ok, %{body: pdf_bytes}} = Xero.Accounting.Invoices.get(token, tenant_id, id, format: :pdf)

# Create invoices (up to 50 at once)
{:ok, _} = Xero.Accounting.Invoices.create(token, tenant_id, %{
  "Type"      => "ACCREC",
  "Contact"   => %{"ContactID" => "uuid"},
  "LineItems" => [%{
    "Description" => "Consulting",
    "Quantity"    => 1.0,
    "UnitAmount"  => 500.0,
    "AccountCode" => "200"
  }],
  "Status" => "AUTHORISED"
})

# Stream all PAID invoices lazily
Xero.Accounting.Invoices.stream(token, tenant_id, statuses: ["PAID"])
|> Enum.each(&process/1)

Summary

Functions

Adds a note to an invoice's history.

Lists attachments on an invoice.

Creates one or more invoices (up to 50 per request, counts as 1 API call).

Deletes a DRAFT or SUBMITTED invoice.

Emails an ACCREC invoice to the contact's primary email address.

Retrieves a single invoice by ID or invoice number.

Gets a specific attachment by filename.

Returns the audit history for an invoice.

Lists invoices. Returns summary-only data for multiple invoices unless :page is specified (paging returns full line item details).

Returns the online payment URL for an AUTHORISED ACCREC invoice.

Returns a lazy Stream of all invoices, auto-paginating through results.

Updates an existing invoice.

Voids an AUTHORISED invoice.

Functions

add_note(t, tid, id, note)

@spec add_note(Xero.Auth.Token.t(), String.t(), String.t(), String.t()) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Adds a note to an invoice's history.

attachments(t, tid, id)

@spec attachments(Xero.Auth.Token.t(), String.t(), String.t()) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Lists attachments on an invoice.

create(token, tenant_id, invoice_or_invoices, opts \\ [])

@spec create(Xero.Auth.Token.t(), String.t(), map() | [map()], keyword()) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Creates one or more invoices (up to 50 per request, counts as 1 API call).

Pass a single map for one invoice, or a list of maps for bulk creation. Uses PUT (Xero's convention for creates with list response).

Required fields

  • "Type""ACCREC" or "ACCPAY"
  • "Contact"%{"ContactID" => "uuid"} or %{"Name" => "Supplier Ltd"}
  • "LineItems" — List of line item maps

Optional fields

  • "Date", "DueDate" — ISO 8601 date strings
  • "Status""DRAFT" (default) | "SUBMITTED" | "AUTHORISED"

  • "Reference", "CurrencyCode", "BrandingThemeID"
  • "LineAmountTypes""Exclusive" | "Inclusive" | "NoTax"

  • "SentToContact" — Mark invoice as sent (boolean)
  • "Url" — Link to an external resource

delete(t, tid, id)

@spec delete(Xero.Auth.Token.t(), String.t(), String.t()) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Deletes a DRAFT or SUBMITTED invoice.

email(token, tenant_id, invoice_id)

@spec email(Xero.Auth.Token.t(), String.t(), String.t()) ::
  :ok | {:error, Xero.Error.t()}

Emails an ACCREC invoice to the contact's primary email address.

Invoice must be type ACCREC and status SUBMITTED, AUTHORISED, or PAID. Also sends to contact persons with IncludeInEmails: true.

get(token, tenant_id, invoice_id, opts \\ [])

@spec get(Xero.Auth.Token.t(), String.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Retrieves a single invoice by ID or invoice number.

Always returns full line item details.

Options

  • :format:pdf to receive the invoice as a PDF binary
  • :unit_dp — Decimal places for unit amounts (4 default)

get_attachment(t, tid, id, filename)

@spec get_attachment(Xero.Auth.Token.t(), String.t(), String.t(), String.t()) ::
  {:ok, binary()} | {:error, Xero.Error.t()}

Gets a specific attachment by filename.

history(t, tid, id)

@spec history(Xero.Auth.Token.t(), String.t(), String.t()) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Returns the audit history for an invoice.

list(token, tenant_id, opts \\ [])

@spec list(Xero.Auth.Token.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Lists invoices. Returns summary-only data for multiple invoices unless :page is specified (paging returns full line item details).

Options

  • :page — Page number (1-indexed, 100/page). Enables full line item details.
  • :statuses — List of statuses: ["DRAFT", "AUTHORISED", "PAID", ...]
  • :contact_ids — List of contact UUIDs
  • :invoice_numbers — List of invoice numbers
  • :ids — List of invoice UUIDs
  • :reference — Reference field exact match
  • :summary_only — Return lightweight response (boolean)
  • :order — Order by field, e.g. "Date DESC", "UpdatedDateUTC ASC"
  • :where — OData filter: ~s(AmountDue > 0 AND Status == "AUTHORISED")
  • :created_by_my_app — Only return invoices created by this app (boolean)
  • :if_modified_sinceDateTime.t() — only return records modified after this time
  • :unit_dp — Number of decimal places for unit amounts (4 default)

online_url(token, tenant_id, invoice_id)

@spec online_url(Xero.Auth.Token.t(), String.t(), String.t()) ::
  {:ok, String.t()} | {:error, Xero.Error.t()}

Returns the online payment URL for an AUTHORISED ACCREC invoice.

stream(token, tenant_id, opts \\ [])

@spec stream(Xero.Auth.Token.t(), String.t(), keyword()) :: Enumerable.t()

Returns a lazy Stream of all invoices, auto-paginating through results.

Accepts all options from list/3 except :page.

Example

Xero.Accounting.Invoices.stream(token, tenant_id,
  statuses: ["AUTHORISED", "PAID"],
  if_modified_since: last_sync)
|> Stream.filter(&(&1["AmountDue"] > 0))
|> Enum.each(&sync_invoice/1)

update(token, tenant_id, invoice_id, attrs)

@spec update(Xero.Auth.Token.t(), String.t(), String.t(), map()) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Updates an existing invoice.

Only DRAFT and SUBMITTED invoices can be fully updated. AUTHORISED invoices: only Reference, SentToContact, Url, and Status can change.

upload_attachment(t, tid, id, filename, content, content_type)

@spec upload_attachment(
  Xero.Auth.Token.t(),
  String.t(),
  String.t(),
  String.t(),
  binary(),
  String.t()
) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Uploads an attachment to an invoice.

void(t, tid, id)

@spec void(Xero.Auth.Token.t(), String.t(), String.t()) ::
  {:ok, map()} | {:error, Xero.Error.t()}

Voids an AUTHORISED invoice.