Skip to content
Docs
Get API Access
Browse the Documentation

Caching and ETags

Metadata and latest-value endpoints send an ETag. Send it back in If-None-Match and an unchanged answer costs a 304 with no body.

Conditional Requests

Endpoints that describe current state (metadata, listings, latest quotes, markets, venues, issuers) send a strong ETag computed from the representation. Store it with the body. Next time, send it back in If-None-Match: if nothing in the answer changed, the API replies 304 Not Modified with no body, and you reuse what you stored.

HTTP
GET /v1/assets/listings/latest?convert=USD&limit=100 HTTP/1.1
Host: api.cantoncap.cc
X-API-Key: ccsk_...

HTTP/2 200
etag: "sha256-2kH9vYxq0Wf4mJr1sN8eTqLb3cZ6aUoP5dGiV7wXyE0"
cache-control: private, no-cache
vary: X-API-Key

GET /v1/assets/listings/latest?convert=USD&limit=100 HTTP/1.1
Host: api.cantoncap.cc
X-API-Key: ccsk_...
If-None-Match: "sha256-2kH9vYxq0Wf4mJr1sN8eTqLb3cZ6aUoP5dGiV7wXyE0"

HTTP/2 304
etag: "sha256-2kH9vYxq0Wf4mJr1sN8eTqLb3cZ6aUoP5dGiV7wXyE0"
const cache = new Map(); // url -> { etag, body }

async function getCached(url) {
  const hit = cache.get(url);
  const response = await fetch(url, {
    headers: {
      "X-API-Key": process.env.CANTONCAP_API_KEY,
      ...(hit ? { "If-None-Match": hit.etag } : {}),
    },
  });
  if (response.status === 304 && hit) return hit.body;

  const body = await response.json();
  if (!response.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
  const etag = response.headers.get("etag");
  if (etag) cache.set(url, { etag, body });
  return body;
}

What Changes the ETag

  • The tag is computed from data only, after the publication rules are applied. The status block (timestamps, request ID) changes on every answer and does not affect it.
  • A new price, a new timestamp, or a record published or withdrawn changes the tag. Internal age thresholds alone do not.
  • The tag is strong. If-None-Match accepts a single tag, a comma-separated list, a weak form (W/"...") of the same tag, or *.
Rate Limits
A 304 is cheaper to send and to process, but it still counts as one request against your per-minute window. Conditional requests save bandwidth and parsing, not quota.

Cache Headers

Cacheable answers carry Cache-Control: private, no-cache and Vary: X-API-Key. A browser or private cache may keep the answer but must revalidate it before use; a shared cache or CDN must not store it, because it is tied to a key. Several history endpoints send the same Cache-Control and Vary without accepting If-None-Match; the reference lists the headers of each endpoint. The issuer X feed answers Cache-Control: no-store and does not support conditional requests.

Endpoints with an ETag

Esc
navigateopenEscclose