# Any endpoint
The CLI has dedicated commands only where it does something an API cannot: files on your disk,
a watched directory, generated code. For everything else there is one command.
```bash
mercemur api /products
```
The method defaults to `GET`, and `/api/v1` is added if you leave it off, so a path copied
straight out of the [reference](/api-reference/introduction) works too.
## Why not curl
Every write to this API is rejected without an `Idempotency-Key` header. `mercemur api` sends one,
reuses it across retries so a repeat is recognised rather than applied twice, and carries your
stored key. A hand-written curl has to remember all three.
```bash
mercemur api POST /discounts --field code=SUMMER --field percentage_basis_points=1000
```
## Fields
| Flag | Value is |
|---|---|
| `--field`, `-f` | Read as JSON: `limit=5` is a number, `active=true` a boolean, `x=null` null |
| `--raw-field`, `-F` | Always a string |
| `--input` | A raw JSON body from a file, or `-` for stdin |
`--raw-field` exists for the case type inference gets wrong. A product code of `123` is a string,
and quietly turning it into a number is a corruption no error message would explain.
On `GET`, `HEAD` and `DELETE` the fields become query parameters instead of a body, because a body
on a read is ignored by most routers and `--field limit=5` would otherwise do nothing at all.
## Paging
```bash
mercemur api /products --field limit=100 --paginate
```
Follows `page.next_cursor` until `has_more` is false and merges every page into **one** JSON
document, so `jq` reads it in a single pass:
```bash
mercemur api /orders --paginate | jq -r '.data[].id'
```
It stops and says so rather than looping: if the API ever repeats a cursor while still reporting
`has_more`, or if you pass 200 pages, you get an error instead of a command that never returns.
Silent truncation would read as "that is all there was".
## Headers, request ids and your rate budget
```bash
mercemur api /products -i
```
```
HTTP 200
Ratelimit-Limit: 300
Ratelimit-Remaining: 299
Ratelimit-Reset: 60
X-Request-Id: req_9d9fa7c7088d20eb1511304f
```
`RateLimit-Remaining` is the only warning you get before a 429, and `x-request-id` is the first
thing support will ask for.
Headers are printed **only** with `--include`, so without it stdout stays a single JSON document
and `| jq` keeps working.
On a failure the request id is reported anyway, on stderr with the error message. Nobody re-runs
a failed write just to collect it.
```
mercemur: GET /api/v1/products: 401, the api key was rejected (request id req_911cf72f...)
```
## Exit codes
The response body is always printed, including on failure, because seeing what the API said is
the point. The exit code is the same taxonomy as every other command:
| Code | Status |
|---|---|
| `0` | 2xx and 3xx |
| `1` | Any other failure |
| `3` | 401 or 403 |
| `4` | 409 or 412 |
| `5` | 404 |
```bash
mercemur api /marketing-campaigns
# exit 3
# { "error": { "code": "insufficient_scope",
# "message": "this api key requires the read_marketing_campaigns scope" } }
```
That makes scope problems obvious rather than something you infer from an empty result.