Get started
Quickstart
Get an API key, read your books and add a receipt in about five minutes.
This guide takes you from nothing to a working integration: you'll read recent entries, add a receipt, and check on it while Oatmilk reads it. You need an Oatmilk account in a company, and a terminal.
1. Get an API key
Open Developers › API keys in Oatmilk and choose Create key. Give it a name you'll recognise later, keep Read and Write for accounting, and copy the key. You only see it once.
Keys start with oat_live_ in production and oat_test_ in staging. Keep yours on your own server, never in browser code or a public repository, and pass it to your code as an environment variable:
export OATMILK_API_KEY="oat_live_…"2. Make your first request
Every action has its own address under /api/v1/accounting/. Read actions accept GET with query parameters, so this lists your five most recent entries:
curl -G https://app.getoatmilk.com/api/v1/accounting/entries.list \
-H "Authorization: Bearer $OATMILK_API_KEY" \
--data-urlencode 'limit=5'3. Read the response
A successful response wraps the result in data. Amounts are whole numbers of cents written as strings, so "4520" is $45.20.
{
"data": [
{
"id": "7f0f6c1e-1c1f-4b5e-9c8d-2f5e8e3c1a10",
"organization_id": "org_synthetic",
"submission_id": "4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"submitted_by": "user_synthetic",
"merchant": "Synthetic Office Supply",
"date": "2026-09-18",
"currency": "CAD",
"amount_minor": "4520",
"tax_minor": "520",
"category_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"payment_account_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"type": "expense",
"status": "reviewed",
"notes": "",
"revision": 3,
"human_corrected": false,
"autopilot_state": "done",
"tags": []
}
]
}Every response also carries an X-Request-Id header. Keep it with your logs: it's the fastest way for us to find a request if you need help.
4. Add a receipt
Changes use POST with a JSON body. uploads.inline adds a receipt of up to 2 MB in one call: send its name, type and bytes as base64. The Idempotency-Key header makes the request safe to retry: send the same key again and the receipt is only added once.
curl https://app.getoatmilk.com/api/v1/accounting/uploads.inline \
-H "Authorization: Bearer $OATMILK_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"filename": "receipt.jpg",
"mimeType": "image/jpeg",
"contentBase64": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAA=="
}'Oatmilk keeps the original file and starts reading it in the background. The response tells you which job to follow:
{
"data": {
"submissionId": "4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"jobId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"generation": 1,
"status": "queued",
"sizeBytes": 182734
}
}5. Check on the job
Reading a receipt takes a few seconds. Ask for the job until its status is completed or failed. A queued or processing job is still working, not finished.
curl -G https://app.getoatmilk.com/api/v1/accounting/jobs.get \
-H "Authorization: Bearer $OATMILK_API_KEY" \
--data-urlencode 'jobId=2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e'{
"data": {
"id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"submission_id": "4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"status": "completed",
"stage": "match",
"generation": 1,
"attempts": 1,
"error_code": null,
"next_attempt_at": "2026-09-30T14:00:05Z"
}
}That's it: the receipt is in the books, matched to its bank transaction when Oatmilk finds one.
Next steps
- Authentication explains permissions, roles and choosing a company.
- Add receipts from your app handles large files with a private upload link.
- Webhooks tell your server when something happens, so you don't have to ask.
- The API reference lists all 775 actions with their fields and examples.