Using DayZero from an AI Agent
This guide is written for the agent, not the human. If you are an LLM-based tool that has been handed a DayZero API token and a task, read this page first — it tells you where every other piece of documentation is, how to find the one endpoint you need without reading all 1,100+, and which conventions will otherwise cost you a round trip.
If you are a person configuring an assistant like Claude, ChatGPT, Cursor or Codex to talk to DayZero, you probably want the MCP Server guide instead — that path uses OAuth in the browser and needs no API token.
Two ways in
| You are… | Use | Auth |
|---|---|---|
| An assistant answering questions or taking actions on a user's behalf in chat | MCP server at https://api.ondayzero.com/mcp — guide |
OAuth 2.1 sign-in in the browser; dz_… tokens do not work here |
| A coding agent, script, workflow or backend calling DayZero directly | REST API at https://api.ondayzero.com/api/v1/… — this guide |
Authorization: Bearer dz_… + x-business-id |
The rest of this page is about the REST path.
Where the documentation is
Everything is plain text or JSON, stable-URL, cacheable, and linked from one place. Read them in this order and stop as soon as you have what you need:
| Step | URL | What you get |
|---|---|---|
| 1 | https://www.ondayzero.com/llms.txt |
Short index of every documentation surface (this table, essentially) |
| 2 | https://www.ondayzero.com/docs/search?q=void+invoice |
JSON: ranked endpoints and guides for a task, each with its markdown_url and openapi_url |
| 3 | https://www.ondayzero.com/docs/reference/{tag}/{operation}.md |
One endpoint: auth, parameters, request/response fields, an example request that validates, curl / Python / JS samples |
| 4 | https://www.ondayzero.com/docs/reference/{tag}/{operation}/openapi.json |
The same endpoint as a self-contained OpenAPI 3.1 document (only the schemas it uses) |
Broader views when you need them:
- Endpoint catalog —
https://www.ondayzero.com/docs/reference/index.md: one line per endpoint (METHOD /path — summary → tag/operation), grouped by tag, ~160 KB for the whole API. Read it once if you'd rather scan than search. - Per-tag bundles —
https://www.ondayzero.com/docs/reference/{tag}.mdand…/{tag}/openapi.json: everything about, say,invoicesin one document. - Guides —
https://www.ondayzero.com/docs/guides/index.md, and any guide as…/docs/guides/{slug}.md. - Full public spec —
https://api.ondayzero.com/api/v1/openapi.json. Large; prefer the slices above.
Every human /docs/** URL also answers Accept: text/markdown with a 303 to its markdown twin, so you can follow links from HTML pages without rewriting URLs:
curl -sL -H "Accept: text/markdown" https://www.ondayzero.com/docs/reference/invoices/create-invoiceAll documentation responses carry an ETag; send If-None-Match on re-reads and you'll get 304s.
Example: search, then read one endpoint
curl -s "https://www.ondayzero.com/docs/search?q=void+invoice&type=endpoint&limit=3"{
"query": "void invoice",
"total": 3,
"results": [
{
"type": "endpoint",
"title": "Void invoice",
"method": "PUT",
"path": "/api/v1/invoices/{invoice_id}/void",
"tag": "invoices",
"slug": "invoices/void-invoice",
"url": "https://www.ondayzero.com/docs/reference/invoices/void-invoice",
"markdown_url": "https://www.ondayzero.com/docs/reference/invoices/void-invoice.md",
"openapi_url": "https://www.ondayzero.com/docs/reference/invoices/void-invoice/openapi.json",
"score": 8.0
}
]
}Then fetch markdown_url. Optional query parameters: type=endpoint|guide, limit=1..50. A missing or empty q returns a 400 with usage hints rather than a 422.
Authenticate
A person creates the token. Tokens (
dz_…) come from Settings → Developers in the DayZero dashboard. There is no endpoint that mints a first token; if you don't have one, ask the human.Find the business. A token can usually reach more than one business, and almost every endpoint needs to know which:
bashcurl -s "https://api.ondayzero.com/api/v1/businesses" \ -H "Authorization: Bearer dz_your_token" \ -H "Accept: application/json"GET /api/v1/businessesis the one common endpoint that does not takex-business-id.Send both headers on everything else:
bashcurl -s "https://api.ondayzero.com/api/v1/invoices?limit=20" \ -H "Authorization: Bearer dz_your_token" \ -H "x-business-id: 01912345-abcd-7000-8000-000000000001" \ -H "Accept: application/json"
If x-business-id is missing you get 401 with code: "AUTH_008"; if the token can't access that business, 401 with code: "AUTH_010". Neither is worth retrying — fix the header or ask the human.
Always send Accept: application/json. Errors are only ever rendered as HTML for browser-style text/html requests, but stating JSON removes the ambiguity.
Conventions that cost a round trip if you guess
- Money is integer cents.
15000is $150.00. Never send150.00. - IDs are UUID v7 strings. Dates are
YYYY-MM-DD; timestamps are RFC 3339 in UTC. - Responses are wrapped: most successful responses look like
{"success": true, "data": …}; mutations may addmessageandcode. Lists put items and paging insidedata. - Lists are cursor-paginated.
dataholdsitems,next_cursor,prev_cursor,has_next,has_prev(and usuallylimit/total). Passlimit(endpoints default to a smaller page; max 1000) andcursorcopied from the previous page'snext_cursor; stop whenhas_nextisfalse. There is no offset paging. Details: Pagination. - Deletes are soft. Deleted records vanish from lists but their IDs stay valid, so a
GETby ID after a delete is not proof the delete failed. - Operation IDs are readable in the public spec (
create_invoice,list_invoices,void_invoice); when two tags share a handler name the tag is appended (list_contacts_customers). The original FastAPI ID is preserved underx-fastapi-operation-idon each operation if you need it. - Examples are real. The
Example requestin every endpoint's.md, the code samples, and therequestBodyexamples in the OpenAPI slices are validated against the request schemas in CI. Copy them and change values; don't invent a shape.
Errors
Every non-2xx response is one envelope (schema ErrorResponse in the spec):
{
"error": "not_found",
"message": "Invoice '0191…' not found",
"code": "NOT_FOUND_006",
"request_id": "3f0e7c2a-…"
}- Branch on
code(stable,CATEGORY_NNN), not onmessage. 400/422validation errors adderrors, a map of field name → message. Fix the named fields and resend once; if the same field fails again, re-read the endpoint's.mdrather than guessing a third time.429iserror: "rate_limited",code: "GEN_005". Back off exponentially (start at 1–2 s) and retry the same request.5xx: retry idempotent requests (GET,PUT,DELETE) with backoff. For aPOSTthat creates something, check first whether it already exists (list with the filter you'd have used, e.g.GET /api/v1/invoices?customer_id=…&status=draft) before re-issuing — there is no idempotency-key header today, so a blind retry can double-create.- Include
request_idwhen reporting a failure to the human; it's what support looks up.
More: Error Handling.
Operate safely
You are usually acting on someone's books. Follow these unless the human has explicitly told you otherwise:
- Read before you write.
GETthe record you're about to change and confirm it is the one the task describes (name, number, amount, status), not just the first search hit. - Treat these as irreversible and confirm with the human first: anything under
/void,/finalize,/post,/approve,/dispose,/merge, bulk endpoints (/bulk,/batch,…-all), andDELETE. Say what you are about to do, with the record's identifier and amount, and wait. - Prefer the narrowest endpoint. Use
PATCHfor one field overPUTof the whole record; use a filtered list over paging through everything; keeplimitsmall unless you need the full set. - Don't loop on
4xx. A401/403/404/422means your request is wrong or you lack access; retrying the identical request will not change that. - Never log or echo the token. Refer to it as "the API token"; the
dz_prefix is enough to identify it. - Stay inside
x-business-id. If a task mentions a different business, switch the header deliberately and say so; don't mix records from two businesses in one operation.
Worked example: void an invoice
Task: "Void invoice INV-1042 for Acme Corp."
# 1. Find the endpoint (once; cache the .md)
curl -s "https://www.ondayzero.com/docs/search?q=void+invoice&type=endpoint&limit=1"
curl -s "https://www.ondayzero.com/docs/reference/invoices/void-invoice.md"
# 2. Identify the record — filter, don't page
curl -s "https://api.ondayzero.com/api/v1/invoices?number=INV-1042&limit=5" \
-H "Authorization: Bearer $DZ_TOKEN" \
-H "x-business-id: $BUSINESS_ID" -H "Accept: application/json"
# 3. Confirm with the human: "Void INV-1042 (Acme Corp, $1,250.00, status sent)? It cannot be undone."
# 4. Act
curl -s -X PUT "https://api.ondayzero.com/api/v1/invoices/$INVOICE_ID/void" \
-H "Authorization: Bearer $DZ_TOKEN" \
-H "x-business-id: $BUSINESS_ID" -H "Accept: application/json"
# 5. Verify
curl -s "https://api.ondayzero.com/api/v1/invoices/$INVOICE_ID" \
-H "Authorization: Bearer $DZ_TOKEN" \
-H "x-business-id: $BUSINESS_ID" -H "Accept: application/json"Report back with the invoice number, the new status from step 5, and the request_id from any error you hit along the way.
Quick reference
| Need | URL |
|---|---|
| Index of everything | https://www.ondayzero.com/llms.txt |
| Find an endpoint | https://www.ondayzero.com/docs/search?q=… |
| One endpoint, markdown | https://www.ondayzero.com/docs/reference/{tag}/{operation}.md |
| One endpoint, OpenAPI | https://www.ondayzero.com/docs/reference/{tag}/{operation}/openapi.json |
| All endpoints, one line each | https://www.ondayzero.com/docs/reference/index.md |
| One tag, markdown / OpenAPI | https://www.ondayzero.com/docs/reference/{tag}.md · …/{tag}/openapi.json |
| Guides as markdown | https://www.ondayzero.com/docs/guides/index.md |
| Full public spec | https://api.ondayzero.com/api/v1/openapi.json |
| Your businesses | GET https://api.ondayzero.com/api/v1/businesses |
| Chat-style access instead | MCP Server |