Public REST API

Pull vendor pricing data into your own tools.

VendorSpies watches OpenAI, Anthropic, Google, Mistral, DeepSeek, xAI, Cohere, Stability AI, and Replicate so you don't have to. Pipe the same data into your own dashboards, alerting systems, or internal cost-forecasting pipelines.

Bearer-token auth
Sliding-window rate limit
paged via `?before` cursor

Overview

The VendorSpies API is REST + JSON. Every endpoint is rate-limited per API key and authenticated with a Bearer token. We currently expose four read-only endpoints; mutations (webhook delivery) will be a separate brief.

Authentication

Send the API key in the standard Authorization header on every request. Keys are issued from your subscriber dashboard and stored in our database as a one-way hash — we cannot recover a lost plaintext, only revoke and replace.

bash
curl \
  https://api.vendorspies.com/api/vendors \
  -H "Authorization: Bearer vsp_live_<your-key>"

Rate limits

Each API key has an hourly budget keyed to the plan frozen on the key at issuance. Team subscribers get 600 requests/hour (configurable via the PUBLIC_API_FOUNDER_HOURLY_LIMIT env var). Every successful response includes x-ratelimit-* headers so you can pace yourself before you hit the wall.

PlanRequests / hourNotes
Team600Frozen at issuance. Shared across all team members up to the 5-seat cap.

Every response carries the trio x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset; a 429 also includes Retry-After in seconds.

Endpoints

GET/api/vendors
PublicVendorList

List every vendor we monitor

Returns the canonical vendor list, alphabetised, with references to each vendor’s pricing page and rate-limit docs.

json
{
  "items": [
    {
      "id": "ckxxx…",
      "slug": "openai",
      "name": "OpenAI",
      "pricingUrl": "https://openai.com/api/pricing/",
      "rateLimitUrl": "https://platform.openai.com/docs/guides/rate-limits"
    }
  ]
}
  • The `:id` field is a stable cuid — embed it don’t depend on the slug for long-term references.
GET/api/vendors/:id/pricing
PublicPricingResponse

Latest per-tier, per-kind snapshot for one vendor

Returns the most recent PriceSnapshot per (tier, kind). Both `PRICE` and `RATE_LIMIT` kinds are included so a single call gives you a complete picture.

bash
curl \
  https://api.vendorspies.com/api/vendors/<vendor-id>/pricing \
  -H "Authorization: Bearer vsp_live_<your-key>"
json
{
  "vendor": { "id": "ckxxx…", "slug": "openai", "name": "OpenAI", "pricingUrl": "…", "rateLimitUrl": "…" },
  "current": [
    {
      "id": "ckyyy…",
      "vendorId": "ckxxx…",
      "tier": "default",
      "kind": "PRICE",
      "currency": "USD",
      "amount": 2.5,
      "capturedAt": "2026-07-21T03:14:07.000Z"
    }
  ]
}
  • Hours-old snapshot is the normal latency — these are the latest rows at the time you ask.
GET/api/vendors/:id/changes
PublicChangeList

History of detected changes for one vendor

Returns Change rows (PRICE and RATE_LIMIT) newest-first, with cursor-style pagination via `?before=<ISO>` and `?limit=<1..200>` (default 50).

bash
curl \
  "https://api.vendorspies.com/api/vendors/<vendor-id>/changes?limit=20" \
  -H "Authorization: Bearer vsp_live_<your-key>"
json
{
  "items": [
    {
      "id": "ckzzz…",
      "vendorId": "ckxxx…",
      "kind": "PRICE",
      "tier": "default",
      "before": { "amount": 2.5, "currency": "USD" },
      "after":  { "amount": 3.0, "currency": "USD" },
      "detectedAt": "2026-07-20T22:11:02.000Z",
      "alertSentAt": "2026-07-20T22:11:09.000Z",
      "vendor": { "id": "ckxxx…", "slug": "openai", "name": "OpenAI", "pricingUrl": "…", "rateLimitUrl": "…" }
    }
  ]
}
  • `before` is exclusive — pass the `detectedAt` of the oldest change in your last page to walk back further.
GET/api/changes
PublicChangeList

Global feed of recent changes across every vendor

Same shape as the per-vendor endpoint, but unscoped. Useful for a single webhook-free ingest that pulls deltas then fans them out to your internal systems.

bash
curl \
  "https://api.vendorspies.com/api/changes?limit=50" \
  -H "Authorization: Bearer vsp_live_<your-key>"
json
{
  "items": [
    { "id": "ckaaa…", "vendorId": "ckxxx…", "kind": "PRICE", "tier": "default", "before": { "amount": 2.5, "currency": "USD" }, "after": { "amount": 3.0, "currency": "USD" }, "detectedAt": "2026-07-20T22:11:02.000Z", "alertSentAt": "2026-07-20T22:11:09.000Z", "vendor": { … } },
    { "id": "ckbbb…", "vendorId": "ckyyy…", "kind": "RATE_LIMIT", "tier": "default", "before": { "rateLimit": 60 }, "after": { "rateLimit": 30 }, "detectedAt": "2026-07-20T11:00:00.000Z", "alertSentAt": null, "vendor": { … } }
  ]
}

Errors

Errors come back as JSON with a stable error string in the `error` field. 429 responses also carry `Retry-After` (seconds) and the standard rate-limit headers; clients should NOT retry inside the window, just wait.

StatusCodeMeaning
400Invalid id / cursorYour request had a malformed `:id`, `limit`, or `before` cursor.
401UnauthorizedMissing, expired, or revoked key.
401Key expiredThe key had an expiry in the past.
401Subscription inactiveThe associated subscriber lapsed. Renew and re-issue a key.
404Vendor not foundThe vendor id is unknown to us.
429Rate limit exceededYou have burned through the hour. Check `Retry-After` (seconds).

Need something we don’t expose yet (webhook delivery to a URL you control, in-tenant CSV exports)? Drop us a line at support@vendorspies.com.