Conventions
Base URL, request/response headers, pagination, and date formats used across the entire API
Every endpoint in the Octopus Cards API follows the same conventions for authentication, headers, pagination, and date formats. Read this once and the rest of the reference reads itself.
Base URL
https://api.octopuscards.ioProduction uses a separate host and credentials - see Environments.
Authentication
All API requests (except login) require a Bearer token in the Authorization header:
curl https://api.octopuscards.io/api/v1/products \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."See the Authentication reference for the full login, refresh, and logout flow.
Request Headers
Every request can include these headers:
| Header | Required | Description |
|---|---|---|
Authorization | Yes (except /auth/login) | Bearer <access_token> - your JWT from the login endpoint |
Content-Type | Yes (POST/PUT/PATCH) | Must be application/json |
X-Request-Id | No | Your own trace ID (KSUID format). If omitted, the server generates one and returns it in the response. Use this to correlate requests across your systems. |
Response Headers
Every response includes:
| Header | Description |
|---|---|
X-Request-Id | The request trace ID - either echoed from your request or server-generated |
List endpoints also include pagination headers:
| Header | Description | Example |
|---|---|---|
X-Page | Current page number (1-based) | 1 |
X-Per-Page | Items per page | 50 |
X-Total-Count | Total items across all pages | 250 |
X-Total-Pages | Total number of pages | 5 |
X-Page-Size | Items in the current page (may be less than X-Per-Page on the last page) | 50 |
X-Has-More | Whether more pages exist | true |
Pagination
List endpoints accept these query parameters:
| Parameter | Default | Range | Description |
|---|---|---|---|
page | 1 | 1+ | Page number (1-based) |
limit | 50 | 1–10,000 | Items per page |
sort | id DESC | - | Sort config as JSON: {"Field":"name","Direction":"ASC"} |
Example:
curl "https://api.octopuscards.io/api/v1/products?page=2&limit=25" \
-H "Authorization: Bearer <token>"Date Format
All date and time fields in requests and responses use RFC 3339 (ISO 8601 with timezone):
2025-01-15T13:00:00Z
2025-01-15T18:30:00+05:30Response Envelope
JWT-authenticated API clients (everything in this reference) always get the raw entity as the response body — the fields documented for the endpoint are the top-level keys.
The cookie-authenticated client portal receives the same payload wrapped in {"success": true, "data": <payload>} for compatibility with its session-based code path. SDK and server-to-server integrations only ever see the raw shape.
Error responses share a single shape regardless of vertical:
{
"error": {
"name": "ValidationException",
"code": "VALIDATION_FAILURE",
"message": "<human-readable message>"
}
}Money: denomination vs amount
Two monetary fields appear across the verticals and they mean different things — don't conflate them.
| Field | Where it appears | What it means |
|---|---|---|
denomination | Voucher products + orders (e.g. an "Amazon $25" card) | Face value of a single voucher unit in the product's display currency. Fixed by the catalog — the customer can't pick an arbitrary value, only one of the listed denominations. |
amount | The total charge debited from the wallet for the order. | For vouchers this is denomination × quantity − discount. For topups it's the customer-requested credit (or, post-charge, the wallet-side total in the wallet's currency). For eSIMs it's the plan price. |
Quick rules:
- Vouchers have both — request with
denomination+quantity, response showsdenomination,quantity, and the computedamount.
- Topups have only
amount— the customer requests a value directly within the variant's min/max.
- eSIMs have only
amount— the customer picks a fixed-price variant, no separate denomination.
Order identifiers
Every order is identified by two values, the same across every vertical:
| Field | Issued by | Purpose |
|---|---|---|
id | Server | Numeric integer, returned in every create response. The canonical handle for GET /…/orders/:id and webhook payloads. |
client_reference | You | Optional, ≤ 255 printable-ASCII characters. Acts as your dedup + lookup key: send the same value twice on create and the second call is rejected with 400 "Duplicate client_reference". Echoed back on every list/detail response under the same name. |
Use client_reference to make retries safe and to look up your own orders without persisting the server-issued id:
# Look up the order you supplied "order-a8f2c1d9" for at create-time
curl "https://api.octopuscards.io/api/v1/orders?client_reference=order-a8f2c1d9" \
-H "Authorization: Bearer <token>"The same ?client_reference= query parameter works on the create-order list endpoint for every vertical. See Idempotency for the full retry pattern.
Pagination Parameter Naming
Two pagination parameter names are in use — also being unified.
| Vertical | Items-per-page parameter |
|---|---|
| Vouchers | limit (default 50, range 1–10,000) |
| Topups | per_page (default 50) |
| eSIM | per_page (default 50) |
page (1-based) is consistent across all verticals. Filtering and sort parameters are per-endpoint.