Receber por email
← Voltar para o catálogo

Xero API Patterns

Use this skill when working with the Xero API - OAuth2 authentication, REST structure, filtering, pagination, rate limiting, error handling, and best practices. Covers Custom Connection OAuth2 flow, tenant ID headers, date formats, and batch operation patterns.

31estrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: Apache-2.0

Como adicionar

/plugin marketplace add wyre-technology/msp-claude-plugins

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/xero-api-patterns/svg)](https://www.skillteca.com.br/skills/xero-api-patterns)

Skills relacionadas

Ver todas de Documentos →

Alerta por categoria

Receba novas skills de Documentos toda segunda

1 email curto, só com as skills novas de Documentos. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Xero API Patterns

Overview

The Xero API is a RESTful JSON API that provides access to accounting data including contacts, invoices, payments, accounts, bank transactions, credit notes, and reports. This skill covers OAuth2 authentication (Custom Connections), query building, pagination, error handling, and performance optimization patterns specific to MSP billing operations.

Authentication

OAuth2 Custom Connections

Xero uses OAuth2 with Custom Connections for machine-to-machine (M2M) integrations. This is the recommended approach for server-side automations and CLI tools.

Token Request:

POST https://identity.xero.com/connect/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(CLIENT_ID:CLIENT_SECRET)

grant_type=client_credentials&scope=accounting.transactions accounting.contacts accounting.reports.read accounting.settings

curl Example:

curl -s -X POST https://identity.xero.com/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -u "${XERO_CLIENT_ID}:${XERO_CLIENT_SECRET}" \
  -d "grant_type=client_credentials&scope=accounting.transactions accounting.contacts accounting.reports.read accounting.settings"

Token Response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI...",
  "expires_in": 1800,
  "token_type": "Bearer",
  "scope": "accounting.transactions accounting.contacts accounting.reports.read accounting.settings"
}

Token Details:

| Field | Value | Description | |-------|-------|-------------| | access_token | JWT string | Bearer token for API requests | | expires_in | 1800 | Token lifetime in seconds (30 minutes) | | token_type | Bearer | Token type for Authorization header | | scope | Space-delimited | Granted OAuth scopes |

Required Headers

All API requests require these headers:

| Header | Value | Description | |--------|-------|-------------| | Authorization | Bearer {access_token} | OAuth2 access token | | xero-tenant-id | Your tenant ID | Target Xero organization | | Content-Type | application/json | JSON content type | | Accept | application/json | JSON response format |

Environment Variables

export XERO_CLIENT_ID="your-client-id"
export XERO_CLIENT_SECRET="your-client-secret"
export XERO_TENANT_ID="your-tenant-id"

Base URL Pattern

All accounting API endpoints follow the pattern:

https://api.xero.com/api.xro/2.0/{resource}

Examples:

https://api.xero.com/api.xro/2.0/Contacts
https://api.xero.com/api.xro/2.0/Invoices
https://api.xero.com/api.xro/2.0/Payments
https://api.xero.com/api.xro/2.0/Accounts

OAuth Scopes

| Scope | Description | |-------|-------------| | accounting.transactions | Read/write invoices, payments, credit notes, bank transactions | | accounting.transactions.read | Read-only access to transactions | | accounting.contacts | Read/write contacts | | accounting.contacts.read | Read-only access to contacts | | accounting.reports.read | Read financial reports | | accounting.settings | Read/write chart of accounts, tax rates | | accounting.settings.read | Read-only access to settings |

Token Management Pattern

class XeroAuth {
  constructor(clientId, clientSecret) {
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.accessToken = null;
    this.expiresAt = 0;
  }

  async getToken() {
    if (this.accessToken && Date.now() < this.expiresAt - 60000) {
      return this.accessToken;
    }

    const credentials = Buffer.from(
      `${this.clientId}:${this.clientSecret}`
    ).toString('base64');

    const response = await fetch('https://identity.xero.com/connect/token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': `Basic ${credentials}`
      },
      body: 'grant_type=client_credentials&scope=accounting.transactions accounting.contacts accounting.reports.read accounting.settings'
    });

    const data = await response.json();
    this.accessToken = data.access_token;
    this.expiresAt = Date.now() + (data.expires_in * 1000);
    return this.accessToken;
  }
}

Request Format

Standard API Request

curl -s -X GET "https://api.xero.com/api.xro/2.0/Contacts" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "xero-tenant-id: ${XERO_TENANT_ID}" \
  -H "Accept: application/json"

POST Request (Create)

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" \
  -H "Accept: application/json" \
  -d '{
    "Type": "ACCREC",
    "Contact": { "ContactID": "abc-123" },
    "LineItems": [
      {
        "Description": "Monthly Managed Services",
        "Quantity": 1,
        "UnitAmount": 2500.00,
        "AccountCode": "200"
      }
    ],
    "Date": "2026-03-01T00:00:00",
    "DueDate": "2026-03-31T00:00:00"
  }'

Response Format

Single Resource:

{
  "Id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "Status": "OK",
  "Contacts": [
    {
      "ContactID": "abc-123",
      "Name": "Acme Corp",
      "EmailAddress": "billing@acme.com",
      "ContactStatus": "ACTIVE"
    }
  ]
}

Collection:

{
  "Id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "Status": "OK",
  "Invoices": [
    {
      "InvoiceID": "inv-456",
      "Type": "ACCREC",
      "InvoiceNumber": "INV-0042",
      "Contact": { "ContactID": "abc-123", "Name": "Acme Corp" },
      "Total": 2500.00,
      "Status": "AUTHORISED"
    }
  ]
}

Filtering

Where Clause Filtering

Xero uses a where query parameter with OData-style expressions:

GET /api.xro/2.0/Contacts?where=Name=="Acme Corp"
GET /api.xro/2.0/Contacts?where=Name.StartsWith("Acme")
GET /api.xro/2.0/Contacts?where=ContactStatus=="ACTIVE"
GET /api.xro/2.0/Invoices?where=Type=="ACCREC"&&Status=="AUTHORISED"
GET /api.xro/2.0/Invoices?where=Contact.ContactID==guid("abc-123")
GET /api.xro/2.0/Invoices?where=AmountDue>0

Important: URL-encode the where parameter value in actual requests.

Where Clause Operators

| Operator | Description | Example | |----------|-------------|---------| | == | Equals | Name=="Acme" | | != | Not equals | Status!="DELETED" | | > | Greater than | AmountDue>0 | | < | Less than | AmountDue<100 | | >= | Greater or equal | Total>=1000 | | <= | Less or equal | Total<=5000 | | && | AND | Type=="ACCREC"&&Status=="PAID" | | || | OR | Status=="DRAFT"||Status=="SUBMITTED" | | .StartsWith() | Starts with | Name.StartsWith("Acme") | | .EndsWith() | Ends with | Name.EndsWith("Corp") | | .Contains() | Contains | Name.Contains("tech") |

If-Modified-Since Header

Use this header to retrieve only records modified after a given date:

GET /api.xro/2.0/Contacts
If-Modified-Since: 2026-02-01T00:00:00

Order Parameter

Sort results using the order parameter:

GET /api.xro/2.0/Invoices?order=Date DESC
GET /api.xro/2.0/Contacts?order=Name ASC

Pagination

Page-Based Pagination

Xero uses page-based pagination with the page query parameter:

GET /api.xro/2.0/Invoices?page=1
GET /api.xro/2.0/Invoices?page=2

Pagination Details:

| Parameter | Description | Default | |-----------|-------------|---------| | page | Page number (1-based) | 1 | | Results per page | Fixed by Xero | 100 |

Detecting End of Pages

When a page returns fewer than 100 results, you have reached the last page:

async function fetchAllInvoices(auth, tenantId) {
  const allItems = [];
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const token = await auth.getToken();
    const response = await fetch(
      `https://api.xero.com/api.xro/2.0/Invoices?page=${page}`,
      {
        headers: {
          'Authorization': `Bearer ${tok
Compartilhar X LinkedIn