Xero
by @byungkyu
Xero API integration with managed OAuth. Manage contacts, invoices, payments, accounts, and run financial reports. Use this skill when users want to interact...
clawhub install xeroπ About This Skill
name: xero description: | Xero API integration with managed OAuth. Manage contacts, invoices, payments, accounts, and run financial reports. Use this skill when users want to interact with Xero accounting data. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). compatibility: Requires network access and valid Maton API key metadata: author: maton version: "1.0" clawdbot: emoji: π§ requires: env: - MATON_API_KEY
Xero
Access the Xero API with managed OAuth authentication. Manage contacts, invoices, payments, bank transactions, and run financial reports.
Quick Start
# List contacts
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/xero/api.xro/2.0/Contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://api.maton.ai/xero/{native-api-path}
Maton proxies requests to api.xero.com and automatically injects your OAuth token and Xero-Tenant-Id header.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
1. Sign in or create an account at maton.ai 2. Go to maton.ai/settings 3. Copy your API key
Connection Management
Manage your Xero OAuth connections at https://api.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=xero&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Create Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'xero'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Get Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2025-12-08T07:20:53.488460Z",
"last_updated_time": "2026-01-31T20:03:32.593153Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "xero",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Specifying Connection
If you have multiple Xero connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/xero/api.xro/2.0/Contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
Security & Permissions
API Reference
Contacts
#### List Contacts
GET /xero/api.xro/2.0/Contacts
#### Get Contact
GET /xero/api.xro/2.0/Contacts/{contactId}
#### Create Contact
POST /xero/api.xro/2.0/Contacts
Content-Type: application/json{
"Contacts": [{
"Name": "John Doe",
"EmailAddress": "john@example.com",
"Phones": [{"PhoneType": "DEFAULT", "PhoneNumber": "555-1234"}]
}]
}
Invoices
#### List Invoices
GET /xero/api.xro/2.0/Invoices
#### Create Invoice
POST /xero/api.xro/2.0/Invoices
Content-Type: application/json{
"Invoices": [{
"Type": "ACCREC",
"Contact": {"ContactID": "xxx"},
"LineItems": [{
"Description": "Service",
"Quantity": 1,
"UnitAmount": 100.00,
"AccountCode": "200"
}]
}]
}
Accounts
#### List Accounts
GET /xero/api.xro/2.0/Accounts
Payments
#### List Payments
GET /xero/api.xro/2.0/Payments
Bank Transactions
#### List Bank Transactions
GET /xero/api.xro/2.0/BankTransactions
Reports
#### Profit and Loss
GET /xero/api.xro/2.0/Reports/ProfitAndLoss?fromDate=2024-01-01&toDate=2024-12-31
#### Balance Sheet
GET /xero/api.xro/2.0/Reports/BalanceSheet?date=2024-12-31
#### Trial Balance
GET /xero/api.xro/2.0/Reports/TrialBalance?date=2024-12-31
Organisation
GET /xero/api.xro/2.0/Organisation
Invoice Types
ACCREC - Accounts Receivable (sales invoice)ACCPAY - Accounts Payable (bill)Code Examples
JavaScript
const response = await fetch(
'https://api.maton.ai/xero/api.xro/2.0/Contacts',
{
headers: {
'Authorization': Bearer ${process.env.MATON_API_KEY}
}
}
);
Python
import os
import requestsresponse = requests.get(
'https://api.maton.ai/xero/api.xro/2.0/Contacts',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
Notes
Xero-Tenant-Id header is automatically injectedYYYY-MM-DD formatwhere query parameter for filteringcurl -g when URLs contain brackets (fields[], sort[], records[]) to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.Error Handling
| Status | Meaning | |--------|---------| | 400 | Missing Xero connection | | 401 | Invalid or missing Maton API key | | 429 | Rate limited (10 req/sec per account) | | 4xx/5xx | Passthrough error from Xero API |
Troubleshooting: API Key Issues
1. Check that the MATON_API_KEY environment variable is set:
echo $MATON_API_KEY
2. Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Troubleshooting: Invalid App Name
1. Ensure your URL path starts with xero. For example:
https://api.maton.ai/xero/api.xro/2.0/Contactshttps://api.maton.ai/api.xro/2.0/ContactsResources
π‘ Examples
# List contacts
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/xero/api.xro/2.0/Contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
π Tips & Best Practices
Xero-Tenant-Id header is automatically injectedYYYY-MM-DD formatwhere query parameter for filteringcurl -g when URLs contain brackets (fields[], sort[], records[]) to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.