# 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.