VendorStacks
On this section

Documentation

Concepts and platform behavior. Endpoint-by-endpoint detail lives in the API Reference; task-oriented walkthroughs in Guides. Prefer markdown? This page is mirrored at /docs.md and everything at once at /llms-full.txt.

Introduction

VendorStacks is a data API over public subprocessor and DPA disclosures. Given an entity (a domain) it answers: does this entity publish a disclosure, where does it live, and which vendors are on it — returned as a structured vendor stack across 13 categories with the quoted disclosure row as evidence. Reverse lookup returns the entities that list a given vendor or category. It is built for GTM enrichment pipelines and AI agents; extraction is deterministic — no LLM, no invented vendors.

Base URL: https://vendorradar-production.up.railway.app . All responses are JSON and carry an X-Request-Id header.

Quick start

1 · Get a key (instant, 25 free credits)
curl -X POST https://vendorradar-production.up.railway.app
/v1/keys \
  -H "Content-Type: application/json" \
  -d '{"email": "you@company.com"}'
2 · Check an entity
curl "https://vendorradar-production.up.railway.app
/v1/check?url=stripe.com" \
  -H "Authorization: Bearer vr_live_..."
3 · Reverse lookup by vendor
curl "https://vendorradar-production.up.railway.app
/v1/prospect?vendor=twilio&category=sms_messaging" \
  -H "Authorization: Bearer vr_live_..."

Agent-first surface

  • [vendorradar-production.up.railway.app /llms.txt](https://vendorradar-production.up.railway.app /llms.txt) — orientation file for LLMs
  • [vendorradar-production.up.railway.app /openapi.json](https://vendorradar-production.up.railway.app /openapi.json) — OpenAPI 3.1 spec for codegen and tool generation
  • [vendorradar-production.up.railway.app /skill](https://vendorradar-production.up.railway.app /skill) — installable SKILL.md for Claude Code and friends
  • [vendorradar-production.up.railway.app /agents](https://vendorradar-production.up.railway.app /agents) — agent integration guide
  • /llms-full.txt — every page of these docs as one markdown document

Authentication

Authenticated endpoints take a Bearer key: Authorization: Bearer vr_live_…. Keys are issued instantly — POST an email to /v1/keys and the key arrives in the same response. No verification click, which means an agent can self-provision mid-task.

The plaintext key is shown exactly once and never stored — only a SHA-256 hash is kept server-side, so a lost key cannot be recovered, only replaced. Rotate keys from the dashboard: create a new key, move traffic, revoke the old one. Revocation is immediate.

Credits & pricing

Everything is prepaid credits, and every lookup costs the same: 1 credit flat. If the entity is already in the index you get the answer in under a second; if it isn't, the API live-scans it automatically (15–90s) at no extra cost. Credits never expire.

OperationEndpointCostLatency
LookupGET /v1/check (live-scans automatically when unindexed) · GET /v1/company/{domain} (never scans)1 credit<1s indexed · 15–90s live scan
Reverse-lookup pageGET /v1/prospect (10 entities)1 credit<1s

Packs: $10 → 1,100 credits · $50 → 6,000 · $250 → 35,000. New keys start with 25 free credits; the free plan allows 5 live scans per day (indexed lookups are uncapped) — any pack removes the cap. Machine-readable pricing is served at /v1/pricing.

When a request would cost more than the key holds, the API answers 402 Payment Required with the exact shortfall and a topup_url — nothing is charged, and the retry after top-up is idempotent. See Errors for the full anatomy.

Usage limits

LimitValueBehavior
Request rate60 requests / minute / key429 with a Retry-After header (seconds). Never charged.
Free-plan live scans5 per dayIndexed lookups are uncapped. Exceeding the allowance returns 429 daily_scan_limit; any credit pack removes the cap.
Concurrent live scans3 per key, platform-wideAdditional scans queue. Concurrent requests for the same domain share one scan (and one charge) — per-domain dedup.
Key issuance3 keys / IP / day on /v1/keys429 beyond that; existing keys are unaffected.
Request body32KB max413 payload_too_large.
  • Set client timeouts to 120s — an unindexed domain triggers an automatic live scan that legitimately takes 15–90 seconds, at the same 1-credit price.
  • The index already covers most entities you'll ask about, so most lookups return in under a second — latency, not price, is the only difference when a live scan kicks in.
  • Need more than 60 rpm? rpm_limit is configurable per key — contact us and we'll raise it.

Errors

Conventional HTTP status codes with a JSON body. No error response ever charges credits. Every response — success or error — carries an X-Request-Id header for correlation; quote it in support requests.

400 validation_error

Example
{ "error": "validation_error",
  "message": "url must be a domain, e.g. acme.com" }

Malformed domain, unknown category slug, bad JSON, or missing required parameter.

401 unauthorized

Example
{ "error": "unauthorized",
  "message": "Missing or invalid API key. Get one instantly: POST https://vendorradar-production.up.railway.app
/v1/keys {\"email\": ...}" }

Missing, malformed, or revoked key. The message self-documents key issuance, so an agent hitting 401 can self-provision without reading docs.

402 payment_required

Example
{ "error": "payment_required",
  "message": "This request costs 1 credit; balance is 0.",
  "remaining_credits": 0,
  "credits_needed": 1,
  "topup_url": "https://vendorstacks.com/app/billing" }

Nothing was charged. Agents: surface topup_url and the exact shortfall to a human, pause, and retry after top-up — the retry is idempotent. See the 402 guide for the full pattern.

404 not_found

Example
{ "error": "not_found",
  "message": "No cached profile for that domain." }

Unknown route, or a /v1/company domain that has never been scanned.

413 payload_too_large

Example
{ "error": "payload_too_large", "message": "Body exceeds 32KB." }

429 rate_limited / daily_scan_limit

Example
{ "error": "rate_limited",
  "message": "60 requests/minute exceeded.",
  "retry_after_seconds": 12 }
Example
{ "error": "daily_scan_limit",
  "message": "Free plan allows 5 live scans per day. Indexed lookups remain available; any credit pack removes the cap.",
  "retry_after_seconds": 41230 }

rate_limited is the per-minute request cap (also sent as a Retry-After header) — back off and retry. daily_scan_limit is the free plan's live-scan allowance (5/day); indexed lookups keep working, and any pack removes the cap. Neither is ever charged.

500 internal_error

Example
{ "error": "internal_error",
  "message": "Something broke on our side.",
  "request_id": "9f6f4a1e-…" }

Include the request_id (also in the X-Request-Id header) when contacting support — it pins the exact log line.

502 scan_failed

Example
{ "error": "scan_failed",
  "message": "Could not reach the target's disclosure pages.",
  "charged": 0 }

Fairness rule: a lookup whose live scan fails — unreachable target, no disclosure located — always charges 0 credits.