Requests and responses
Envelopes, pagination, filters, units, idempotency and rate limits.
The base URL is https://api.boxafox.com. Requests and responses are JSON with snake_case fields.
Envelopes
A single object:
{ "data": { "id": "…" }, "message": "Proxy user created." }A list:
{ "data": [], "message": "OK", "page": 1, "per_page": 25, "total_count": 137 }- A create answers
201with the full object. - A delete answers
200with{ "data": { "id": "…", "deleted": true } }. 204is never used: every answer has a body.- Every response carries an
X-Request-Idheader (req_…). Include it when you contact support.
Errors have their own shape: see Errors.
Pagination and sorting
| Parameter | Values | Default |
|---|---|---|
page | 1 or more | 1 |
per_page | 1–100 | 25 |
sort_by | A field name, or the name with _desc | created_at_desc |
total_count is exact. Each list endpoint names the fields it can sort by.
Filters
Filters are query parameters named after the field:
| Form | Meaning | Example |
|---|---|---|
<field>= | Exact match | status=active |
min_<field>=, max_<field>= | Range, for numbers and dates | min_created_at=2026-10-01T00:00:00Z |
like_<field>= | Contains, case-insensitive; % is a wildcard | like_username=scraper |
not_<field>= | Not equal | not_status=disabled |
metadata.<key>= | Match a metadata value | metadata.project=shop |
metadata.exists_<key>=1 | The metadata key is set | metadata.exists_project=1 |
A parameter the endpoint does not know is refused with 400 validation_error, so a typo never silently returns everything.
Units and formats
| Thing | Format |
|---|---|
| Money | Whole cents, with currency: "EUR". |
| Data | Whole bytes. 1 GB is 1,073,741,824 bytes. |
| Time | RFC 3339 in UTC, for example 2026-10-05T14:03:00Z. Dates alone are YYYY-MM-DD. |
| Ids | UUIDs. Proxy users can also be addressed by username, orders by number (ORD-2026-000123). |
| Countries | ISO 3166-1 alpha-2 in lowercase (de). |
| Enums | Lowercase snake_case strings. |
Idempotency
POST /v1/checkout needs an Idempotency-Key header (1–255 characters); other POST requests accept one. Use a new random value for each purchase and repeat the same value when you retry.
- The same key with the same body within 24 hours returns the first response again, without buying twice.
- The same key with a different body answers
409 idempotency_conflict. - A repeat while the first request is still running answers
409 idempotency_in_flightwithRetry-After: 2.
Rate limits
The public API allows 20 requests per 2 seconds per account. Every response says where you stand:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the window. |
X-RateLimit-Remaining | Requests left in the window. |
X-RateLimit-Reset | When the window resets, in Unix seconds. |
Over the limit the API answers 429 rate_limited with a Retry-After header. A call to a list endpoint counts as one request whatever its count.