Skip to main content
GET /v1/prices/history returns the reviewed price history: every published price, old rates included, as it stood at an instant you choose. Call it instead of keeping a copy of the prices; pin the instant to make a computation reproducible.

Query parameters

Response

200 OK

Price rows

A price line is one provider, source, resource, dimension, unit, currency and tier. Its current price at asOf is its row with the newest recordedAt; the older rows are its history. New fields may be added to the response. Ignore fields you do not recognize.

Pinning with asOf

A row is in the answer at asOf when it was published at that instant. A price published on day 1 and withdrawn on day 2 is in the answer at a day-1 asOf and not at a day-2 one. Nothing that happens later changes the answer at an earlier asOf, so the same asOf always returns the same rows, and approvalStatus is the status at asOf, not today’s. asOf cannot be later than 15 minutes ago: prices land shortly after the instant they carry, and a read closer to now could miss rows that a later read at the same instant would see. A later value is 400 as_of_too_recent. Store the response’s asOf beside anything you compute from it; asking again with it reproduces the input exactly. With alias= that holds while alias.revision is unchanged (Alias groups).

Paging

Rows are ordered by contentHash. While nextCursor is not null, request the next page with cursor and limit only. Ask only for the providers you need: one large provider can be tens of thousands of rows.
  • What a cursor pins: asOf, providers, the alias group at the revision the first page read, and the position. Every page of one walk reads the same asOf. Sending asOf, providers or alias beside a cursor is 400 invalid_query (error.field is cursor).
  • What it does not pin: limit. Each request uses the limit sent with it, or 5,000 when none is sent. Send the same limit on every page.
  • Lifetime: a cursor does not expire. Its asOf is in the past, so the rows behind it never change and a walk can continue later. A cursor with alias stops working once the group changes.
  • After 409 alias_changed: the group changed between pages (its members or its name, or it was deleted), so the pages already read may belong to the old group. Discard them and start again from the first page, without a cursor. To read the same instant, send the first page’s asOf back with the same alias and providers; without asOf, the new walk reads a newer instant.
  • After 429 rate_limited: the endpoint has its own rate limit. Wait retry-after seconds and send the same request again; the cursor stays valid.
Node.js 18 or later (built-in fetch)
Python

Alias groups

alias= narrows the answer to one alias group: the same resource at every provider that sells it, each under its own name. The rows are the ordinary rows of the group’s members; nothing is merged or converted. The answer adds the group:
  • alias.id is the group’s stable id; alias.name is its display name, which can change. alias= accepts either.
  • members is the whole group. Rows are served for the members whose provider is in providers; without providers, those are the active USD-priced providers that sell it.
  • An unknown group is 404 alias_not_found.
  • The rows are pinned to asOf; the group is not. Membership is always the group as published when you read it: there is no parameter to ask for an earlier revision, so the same asOf can return other rows after the group changes. Store alias.revision beside asOf to tell whether the group changed since you last read it. A different revision means the group was saved again: its members may have changed (the alias.member_added and alias.member_removed webhook events say how), or only its name, or nothing visible. Compare members to know.
  • If the group changes while you page through it (any new revision, or it is deleted), the next page is 409 alias_changed: start again from the first page (Paging).
  • A member is an exact resource name: a renamed resource’s earlier rows are included only if the group lists the old name too.

Prices that are not money

price is in currency, which is not always USD. snowflake prices in two steps: what a service consumes in credits (unit: credit_per_token, currency: SNOWFLAKE_AI_CREDIT or SNOWFLAKE_PLATFORM_CREDIT) and what a credit costs (unit: usd_per_credit, currency: USD, per cloud, region and edition in pricingTier). The cost in USD is the consumption rate times the usd_per_credit price of the same credit type. These rows are served only when you name the provider (providers=snowflake), so code that sums price as money never receives them by default.

Renamed resources

When a provider renames a resource, rows under the old name carry renamedTo: the name the resource is listed under at asOf. Join on source and renamedTo to read one history across the rename. Rows of a resource that was never renamed have no renamedTo.

Errors

GET /v1/providers

The provider directory: the slugs to use in providers and in webhooks.
status is active, or pending while a provider is being added (a webhook can already subscribe to it). activatedAt is null for providers older than the directory. freshness is fresh, stale or unknown.

GET /v1/comparison/aliases

The published alias groups.
200 OK
Each entry of groups has an id, a resource, a revision, updatedAt and its members (provider, resource). The same group has other field names elsewhere: alias= and a webhook’s alias groups take the id or the name; a webhook stores the id. A group whose members are all no longer listed (their provider or sources were retired) is listed with no members and "retired": true. version is the version of the whole catalog: it goes up with every change to any group, deletions included, so it can be higher than every listed group’s revision. unpriced lists the members whose resource has not been seen priced for a week. resources lists every resource the catalog knows, with comparisonResource: the name of its group or, when it is in none, its canonical id (else its own name). canReview is always false for an API key.

GET /v1/catalog

GET /v1/catalog?provider=openai lists what you can filter a webhook on for one provider: resources (each with resource, canonicalResource and dimensions) and docs (each with the document slug doc and its url).
200 OK
A provider that has no catalog yet answers "updatedAt": null with empty lists. An unknown or missing provider is 404 provider_not_found; note that the price history answers an unknown slug in providers with 400 invalid_query instead.