x0 for AI agents and API clients
How an AI agent (or any HTTP client) should fetch Xero-backed data from x0.
The Excel OData guide is for humans clicking through Excel. This page is the one agents should read.
Why x0 instead of calling Xero directly
- Stable table-shaped OData (
valuearrays) for Excel and agents - Server-side caching, rate-limit awareness, and sync progress
- One Bearer token per customer — no Xero OAuth dance in the agent
- Scoped API keys (
xero.accounts.read, wildcards, expiry)
Quick start (minimum)
First discover context:
GET https://api.x0.co.nz/odata/v1/X0
Authorization: Bearer x0_live_<token_id>.<secret>
Then data:
GET https://api.x0.co.nz/odata/v1/Accounts
Authorization: Bearer x0_live_<token_id>.<secret>
Optional tenant:
GET https://api.x0.co.nz/odata/v1/Accounts?tenant_id=<xero-tenant-guid>
Authorization: Bearer x0_live_<token_id>.<secret>
Or header: X-Xero-Tenant-Id: <xero-tenant-guid>
Response shape (OData v4):
{
"@odata.context": "https://api.x0.co.nz/odata/v1/$metadata#Accounts",
"value": [ { "AccountID": "...", "Code": "200", "Name": "Sales", "...": "..." } ]
}
Discovery
| Step | Request |
|---|---|
| 1. Who am I / connection | GET /odata/v1/X0 (scope xero.settings.read) |
| 2. List entity sets | GET /odata/v1 |
| 3. Schema | GET /odata/v1/$metadata |
| 4. Connected orgs | GET /odata/v1/Tenants |
| 5. Table catalog | GET /odata/v1/Tables |
| 6. Data | GET /odata/v1/Accounts, Items, CreditNotes, PurchaseOrders_Table, Journals_Table, … |
X0 returns one row: customer name/email/plan, tenant + last sync, API key label/prefix/scopes/environment, and DocsUrl / PortalUrl / ApiBaseUrl.
How tables join: data-schema.md (dashboard diagram + mermaid). MCP: get_schema_diagram.
Interactive OpenAPI: https://api.x0.co.nz/docs
Auth
- Issue a key in the customer portal (shown once).
- Format:
x0_live_<ULID>.<secret>orx0_test_<ULID>.<secret> - Headers (any of these works):
Authorization: Bearer <full-key>Authorization: Basic— username = token id (x0_live_<ULID>), password = secret; or full key in either fieldX-Api-Key: <full-key>- Keys have scopes and expiry. Missing scope →
403. Bad/expired key →401withWWW-Authenticate: Bearer, Basic realm="x0". - Optional: send
Accept-Encoding: gzip(Standard+ /gzip_responsesoption). x0 may replyContent-Encoding: gzip.
Never put the secret in URLs or chat logs. Prefer env vars / secret stores.
Query options agents should prefer
| Option | Use |
|---|---|
$select=Code,Name,Type |
Smaller payloads |
$filter=Status eq 'ACTIVE' |
Narrow rows |
$top=100 / $skip=100 |
Page through large sets |
$orderby=Code asc |
Stable ordering |
$count=true |
Include @odata.count |
Example:
GET /odata/v1/Accounts?$select=Code,Name,Type&$filter=Status eq 'ACTIVE'&$top=200
Authorization: Bearer …
Agent workflow (recommended)
- Confirm base URL (
https://api.x0.co.nzor localhttp://127.0.0.1:8001). GET /odata/v1/Tenants— pickTenantIdif more than one org.GET /odata/v1/Tables— see what is available for this key’s scopes.- Fetch entity sets with
$select/$filter/$top. - On
502/ emptyvaluewith note fields — data may still be syncing; check portal or retry later. - On
429-class upstream issues — back off; x0 logs rate limits server-side.
Skill vs MCP
| Approach | When |
|---|---|
| How-to page (this doc) | Any agent / Yaak / curl / n8n that can HTTP |
| Cursor skill | Teach Cursor how to call x0 correctly in this repo |
| MCP server | When chat agents should invoke tools (list_tables, describe_table, query_odata) without writing HTTP |
A skill is enough for coding agents that already have Shell/fetch. Use the MCP servers when the product goal is “ask natural language → understand schema + live Xero tables” inside Cursor/Claude without the user pasting URLs.
MCP setup (x0 + xerosim)
Shipped under shim/agent_mcp/ — see agent_mcp/README.md.
cd shim
python3 -m venv .venv-mcp
.venv-mcp/bin/pip install -r agent_mcp/requirements-mcp.txt
Cursor / Claude Desktop example:
{
"mcpServers": {
"x0": {
"command": "/path/to/shim/.venv-mcp/bin/python",
"args": ["-m", "agent_mcp.x0"],
"cwd": "/path/to/shim",
"env": { "X0_API_BASE_URL": "https://api.x0.co.nz" }
}
}
}
Tools expose per-table fields (name, type, description, sample value), linkages, cache/auth rules, and optional live query_odata when X0_API_KEY is set in the server env (never in tool args).
Full customer guide: mcp-agents.md (also in portal Guides).
Machine-friendly entry points
- OData service document:
/odata/v1 - OpenAPI UI:
/docs - This markdown: ship with the shim; also browsable in Admin → Documentation
- Yaak recipe: yaak.md
Related
- Documentation index · Glossary
- odata.md — full OData reference
- data-schema.md — ER diagram / mermaid
- yaak.md — GUI client setup
- agentic-query.md — in-portal Ask x0
- xero-simulator.md — hosted Xero sandbox (Professional+)
- support-queries.md — if the agent should open a support ticket instead