Skip to content

Conditional requests

Catalog and market data reads carry an ETag. Send it back in If-None-Match and, while the data hasn’t changed, the API answers 304 Not Modified with no body, so polling an unchanged resource costs no transfer and no decoding.

GET /v1/events/4102/metrics
Authorization: Bearer tx_live_…
HTTP/1.1 200 OK
ETag: W/"q2Jx0kVd3H9cS8hT1mNw4A"
Cache-Control: private, no-cache
GET /v1/events/4102/metrics
If-None-Match: W/"q2Jx0kVd3H9cS8hT1mNw4A"
HTTP/1.1 304 Not Modified
ETag: W/"q2Jx0kVd3H9cS8hT1mNw4A"
  • The ETag of these reads is weak: a hash of the JSON body, so it differs per plan, filter and query. Keep one per request URL.
  • If-None-Match may list several ETags, comma-separated, or *; tags compare weakly (a W/ prefix is ignored).
  • A 304 carries the current ETag and the rate limit headers. It still counts as a request against your quota.
  • The seat map overlay (GET /v1/events/{id}/map/overlay) has a strong ETag that changes with the seat map, the snapshot and the pricing. Seat map artifacts (GET /v1/seatmaps/{hash}) are immutable: their strong ETag is the artifact’s hash.
  • Browsers revalidate on their own (Cache-Control: private, no-cache); you only send If-None-Match yourself from servers and scripts.

If-None-Match is accepted by:

Area Endpoints
Catalog GET /v1/events, /v1/events/{id}, /v1/regions, /v1/catalog/facets, /v1/search, /v1/attractions/{id}, /v1/attractions/{id}/events, /v1/venues/{id}, /v1/venues/{id}/events, /v1/calendar/days, /v1/calendar/items
Market data GET /v1/events/{id}/metrics, /v1/events/{id}/series, /v1/events/{id}/sales, /v1/events/{id}/listings, /v1/events/{id}/listings/changes, /v1/events/{id}/inventory/changes, /v1/sales/feed, /v1/sales/summary, /v1/movers, /v1/compare/series
Seat maps GET /v1/events/{id}/map, /v1/events/{id}/map/overlay, /v1/seatmaps/{hash}

The API reference lists the If-None-Match parameter and the 304 response on each of them.

Both SDKs expose the ETag of every response and accept ifNoneMatch (TypeScript) / if_none_match (Python) on the operations above. A 304 is not an error: the call returns a NotModified value carrying the current etag, headers and rate limit state, and the result type says so only when you pass the option.

import { NotModified, Status302 } from "@status302/sdk";
const status302 = new Status302({ apiKey: process.env.STATUS302_API_KEY });
const first = await status302.request("get", "/v1/events/{id}/metrics", { path: { id: 4102 } });
// first.data: the metrics; first.etag: 'W/"q2Jx0kVd3H9cS8hT1mNw4A"'
const next = await status302.get("/v1/events/{id}/metrics", { path: { id: 4102 }, ifNoneMatch: first.etag });
if (next instanceof NotModified) console.log("unchanged");
else console.log("new metrics", next.items);
import os
from status302 import NotModified, Status302
with Status302(api_key=os.environ["STATUS302_API_KEY"]) as status302:
first = status302.with_response.get_event_metrics(4102) # APIResponse: .data, .etag, .status, …
nxt = status302.get_event_metrics(4102, if_none_match=first.etag)
if isinstance(nxt, NotModified):
print("unchanged")
else:
print("new metrics", nxt["items"])

To revalidate without tracking ETags yourself, give the client an ETag cache. Every GET whose response carried an ETag is stored by URL; the next GET of that URL sends If-None-Match, and on 304 the client returns the stored body as if it had been sent again (status is 304 on the full response). Calls that pass their own ifNoneMatch / if_none_match bypass the cache.

import { MemoryETagCache, Status302 } from "@status302/sdk";
const status302 = new Status302({ apiKey: process.env.STATUS302_API_KEY, etagCache: new MemoryETagCache(1000) });
import os
from status302 import MemoryETagCache, Status302
status302 = Status302(api_key=os.environ["STATUS302_API_KEY"], etag_cache=MemoryETagCache(1000))

MemoryETagCache keeps the most recently used entries (1000 by default) in memory. Entries never go stale: an ETag identifies its body, so a 304 proves the stored copy is current. To share a cache between processes, implement the ETagCache interface (get and set of a CachedResponse by key; async methods are fine in TypeScript) over your own store.