# Making requests

> Addresses, methods, the response envelope, headers and size limits.

Source: https://app.getoatmilk.com/docs/requests

The Oatmilk API is a set of named actions, the same ones the Oatmilk app uses. Each action has its own address, takes a JSON object, and returns a JSON object. There are no nested resource paths to learn: if you know an action's name, you know its address.

```http
POST https://app.getoatmilk.com/api/v1/accounting/invoices.create
```

## Methods

- **POST** works for every action. Send the input as a JSON body with `Content-Type: application/json`.
- **GET** also works for read actions, with the input in the query string. It's handy for quick checks and caching proxies, but values arrive as text, so use POST for anything with lists or nested objects.

An action that changes something refuses GET with `METHOD_NOT_ALLOWED`. Each action's page in the [API reference](https://app.getoatmilk.com/docs/api.md) shows which methods it accepts.

## The response envelope

A successful response has one field, `data`, holding the action's result:

```json
{ "data": { "id": "7f0f6c1e-1c1f-4b5e-9c8d-2f5e8e3c1a10", "status": "sent" } }
```

A refused or failed request has one field, `error`, with a stable `code` you can branch on and a `message` you can show a person:

```json
{ "error": { "code": "INVALID_INPUT", "message": "Amount needs a valid value. Check this field and try again.", "field": "amountMinor", "docUrl": "https://app.getoatmilk.com/docs/errors#invalid-input" } }
```

`field` names the first problem when there is one, and `docUrl` links to what the code means. Some errors also carry `dashboardUrl` or `portalUrl`: the page where a person can finish the step. See [Errors](https://app.getoatmilk.com/docs/errors.md).

## Headers

| Header | Meaning |
| --- | --- |
| `X-Request-Id` | A unique ID for this request. Keep it in your logs and include it when you ask for help. |
| `X-Accounting-API-Version` | The date of the API contract this response follows. |
| `Retry-After` | On a 429 response: how many seconds to wait before retrying. |
| `WWW-Authenticate` | On a 401 response: says a bearer credential is required. |

## Limits

| Limit | Value |
| --- | --- |
| Requests per API key | 120 per minute |
| JSON body | 3 MB |
| Time to send the body | 15 seconds |
| File in `uploads.inline` | 2 MB |
| File through an upload link | 50 MB |

## Browser requests

The API answers cross-origin requests, so a tool running in a browser can call it. That doesn't make it safe to put an API key in a web page: anyone who opens the page can read the key. Call Oatmilk from your own server, or use OAuth so each person signs in with their own account.

## The OpenAPI document

`https://app.getoatmilk.com/api/openapi.json` describes every action in OpenAPI 3.1, generated from the same definitions the API checks requests against. Import it into Postman, Insomnia or a code generator, or point an AI tool at it. Its `webhooks` section describes every event Oatmilk sends.
