---
title: "Conventions"
description: "Amounts, ids, metadata, idempotency, pagination and rate limits."
image: "https://docs.ordercard.io/og.png"
---

> API Reference Index
> Fetch the complete API index at: https://docs.ordercard.io/api/llms.txt
> Use this file to discover all available pages before exploring further.

# Conventions

## Requests and responses

Send JSON with `Content-Type: application/json` and read JSON back. A single record comes back as the object itself, with an `object` field naming its type. Timestamps are ISO 8601 in UTC.

## Amounts

Every amount is an **integer in minor units**: cents for USD, so `2500` is $25.00. This holds for requests and responses alike. Each gateway receives the amount in whatever format it expects.

`currency` is a three-letter code and defaults to `USD`.

## Ids

Ids carry a prefix that tells you what they are, followed by a sortable ULID:

| Prefix | Record |
| --- | --- |
| `tok_` | A vaulted card (its token) |
| `cus_` | A customer |
| `gw_` | A gateway |
| `txn_` | A transaction |
| `we_` | A webhook endpoint |
| `evt_` | A webhook event |

## Metadata

Cards, transactions and customers take `metadata`: keys and values of your own, like an order id. It is returned on the record and in its webhooks, and shown in the dashboard.

- Up to 50 keys. A key starts with a letter and uses only letters, digits, `_` and `-`, up to 40 characters.
- Values are text, up to 500 characters. Numbers, `true`/`false` and nested objects are refused; send them as text.
- Sending `metadata` replaces all of it. To change one key, send the whole set again; send `{}` to clear it.
- Metadata is stored as plain text, so never put card numbers or other secrets in it. A value containing anything that passes for a card number is refused.

```json
{ "metadata": { "order_id": "1042", "channel": "web" } }
```

## Idempotency

Send an `Idempotency-Key` header with every `POST` that moves money. If the request is retried with the same key and the same body within 24 hours, you get the first answer back, marked with an `Idempotent-Replayed: true` header, and nothing runs twice.

```bash
curl -X POST https://api.ordercard.io/v1/gateways/gw_01jaxr2d5f8g0h3j6k9m2n5p8q/purchase \
  -H "Authorization: Bearer $ORDERCARD_SECRET_KEY" \
  -H "Idempotency-Key: order-1001-attempt-1" \
  -H "Content-Type: application/json" \
  -d '{ "payment_method_token": "tok_01jaxqk0pz7r8w5m3n2b4c6d8e", "amount": 2500 }'
```

- A key reused with a different body answers `409` with `idempotency_key_reused`.
- While the first request with a key is still running, a second one answers `409` with `idempotency_in_progress`.
- Declines (`402`) are remembered like successes. Server errors (`5xx`) are not, so a request that failed on our side can be retried with the same key.
- Refused requests (invalid input, a missing permission, a conflict) are not remembered either: fix the request and send it again with the same key.
- Keys are remembered per API key. A retry sent with a different API key runs as a new request, and a charge can still never run twice with the same `Idempotency-Key`.
- Keys are at most 255 characters. Use something tied to the business action, like an order number plus attempt.

## Pagination

List endpoints return a page of records under `data`, newest first, with cursors to move between pages:

```json
{
  "data": [ { "object": "transaction", "id": "txn_…" } ],
  "links": { "first": null, "last": null, "prev": null, "next": "https://api.ordercard.io/v1/transactions?cursor=eyJ…" },
  "meta": { "path": "https://api.ordercard.io/v1/transactions", "per_page": 25, "next_cursor": "eyJ…", "prev_cursor": null }
}
```

Pass `limit` (1 to 100, default 25) and `cursor` (a `next_cursor` or `prev_cursor` value). When `next_cursor` is `null` you have reached the end.

## Rate limits

Each API key can make 300 requests per minute. Above that, requests answer `429` with the code `rate_limited` and a `Retry-After` header saying how many seconds to wait.

Source: https://docs.ordercard.io/api/conventions/index.mdx
