On this section
API Reference
Base URL https://vendorradar-production.up.railway.app
. Authenticated endpoints take Authorization: Bearer vr_live_…. All responses are JSON and carry an X-Request-Id header. Concepts, limits, and full error semantics live in Documentation.
Keys
/v1/keysIssue an API key instantly. POST an email, get a key in the same response — no verification click. New keys receive 25 free credits (free plan: 5 live scans/day; indexed lookups uncapped).
| Parameter | In | Required | Description |
|---|---|---|---|
| body | required | Email address to associate with the key. JSON body field. |
curl -X POST https://vendorradar-production.up.railway.app
/v1/keys \
-H "Content-Type: application/json" \
-d '{"email": "you@company.com"}'const res = await fetch("https://vendorradar-production.up.railway.app
/v1/keys", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "you@company.com" }),
});
const { api_key, credit_balance } = await res.json();HTTP/1.1 201 Created
{
"api_key": "vr_live_8f4b2c91d3e7a650",
"email": "you@company.com",
"credit_balance": 25,
"free_tier": true,
"note": "Key shown once. Store it now."
}- ›The key is returned exactly once and cannot be recovered — store it immediately.
- ›400 if the email is malformed; 429 if too many keys were requested from the same source recently.
Lookups
/v1/check?url={domain}Check an entity: does this domain publish a subprocessor/DPA disclosure, where does it live, and which vendors are on it. 1 credit flat — indexed answers return <1s; unindexed domains live-scan automatically (15–90s) at the same price.
| Parameter | In | Required | Description |
|---|---|---|---|
| url | query | required | Domain or URL of the entity to check, e.g. acme.com. Scheme and path are normalized away. |
| fresh | query | optional | true forces a live re-scan even when the entity is indexed. Same 1-credit price, just slower (15–90s). |
| category | query | optional | Restrict the response to one category slug (see /v1/vendors), e.g. sms_messaging. |
| Authorization | header | required | Bearer vr_live_… API key. |
curl "https://vendorradar-production.up.railway.app /v1/check?url=notify-hq.com" \ -H "Authorization: Bearer $VENDORSTACKS_KEY"
const res = await fetch(
"https://vendorradar-production.up.railway.app
/v1/check?url=" + encodeURIComponent("notify-hq.com"),
{ headers: { Authorization: `Bearer ${process.env.VENDORSTACKS_KEY}` } },
);
const data = await res.json();
// data.found, data.vendor_stack, data.credits_usedHTTP/1.1 200 OK
{
"domain": "notify-hq.com",
"found": true,
"cache": "hit",
"scanned_at": "2026-07-21T09:14:02Z",
"disclosure_url": "https://notify-hq.com/legal/subprocessors",
"vendor_stack": {
"sms_messaging": [
{
"vendor": "twilio",
"confidence": "vendor_keyword",
"evidence": {
"source": "https://notify-hq.com/legal/subprocessors",
"quote": "Twilio Inc. — SMS and voice message delivery"
}
}
],
"email": [
{
"vendor": "sendgrid",
"confidence": "vendor",
"evidence": {
"source": "https://notify-hq.com/legal/subprocessors",
"quote": "SendGrid (Twilio Inc.) — transactional email"
}
}
],
"payments": [
{
"vendor": "stripe",
"confidence": "vendor_keyword",
"evidence": {
"source": "https://notify-hq.com/legal/dpa",
"quote": "Stripe, Inc. — payment processing services"
}
}
]
},
"sends_sms": true,
"credits_used": 1,
"credit_balance": 24
}- ›found: false means no disclosure page was located for the entity — it does not mean the entity uses no vendors. See confidence tiers below.
- ›Fairness rule: if a live scan fails to locate a disclosure page, credits_used is 0.
/v1/company/{domain}Full profile read for an entity: complete vendor stack across all 13 categories, disclosure sources, and scan history. Guaranteed instant — this endpoint never triggers a scan.
| Parameter | In | Required | Description |
|---|---|---|---|
| domain | path | required | The entity's domain, e.g. notify-hq.com. |
| Authorization | header | required | Bearer vr_live_… API key. |
curl "https://vendorradar-production.up.railway.app /v1/company/notify-hq.com" \ -H "Authorization: Bearer $VENDORSTACKS_KEY"
const res = await fetch("https://vendorradar-production.up.railway.app
/v1/company/notify-hq.com", {
headers: { Authorization: `Bearer ${process.env.VENDORSTACKS_KEY}` },
});
const profile = await res.json();HTTP/1.1 200 OK
{
"domain": "notify-hq.com",
"found": true,
"first_seen": "2026-03-02T11:40:19Z",
"scanned_at": "2026-07-21T09:14:02Z",
"disclosure_sources": [
"https://notify-hq.com/legal/subprocessors",
"https://notify-hq.com/legal/dpa"
],
"vendor_stack": {
"sms_messaging": [{ "vendor": "twilio", "confidence": "vendor_keyword", "evidence": { "...": "..." } }],
"email": [{ "vendor": "sendgrid", "confidence": "vendor", "evidence": { "...": "..." } }],
"payments": [{ "vendor": "stripe", "confidence": "vendor_keyword", "evidence": { "...": "..." } }],
"cloud_infra": [{ "vendor": "aws", "confidence": "vendor", "evidence": { "...": "..." } }]
},
"sends_sms": true,
"credits_used": 1,
"credit_balance": 23
}- ›Returns 404 with found: false (0 credits) if the domain has never been scanned — use /v1/check, which live-scans unindexed domains automatically.
Prospecting
/v1/prospect?vendor=&category=&page=Reverse lookup: list entities by vendor or category. Returns every entity in the index whose disclosure names the given vendor, optionally narrowed by category — 10 entities per page, each with its quoted evidence.
| Parameter | In | Required | Description |
|---|---|---|---|
| vendor | query | optional | Canonical vendor slug, e.g. twilio. At least one of vendor or category is required. |
| category | query | optional | Category slug, e.g. sms_messaging. Combine with vendor to narrow. |
| page | query | optional | 1-based page number. Default 1. Each page of 10 entities costs 1 credit. |
| Authorization | header | required | Bearer vr_live_… API key. |
curl "https://vendorradar-production.up.railway.app /v1/prospect?vendor=twilio&category=sms_messaging&page=1" \ -H "Authorization: Bearer $VENDORSTACKS_KEY"
const params = new URLSearchParams({
vendor: "twilio",
category: "sms_messaging",
page: "1",
});
const res = await fetch("https://vendorradar-production.up.railway.app
/v1/prospect?" + params, {
headers: { Authorization: `Bearer ${process.env.VENDORSTACKS_KEY}` },
});
const { companies, total } = await res.json();HTTP/1.1 200 OK
{
"vendor": "twilio",
"category": "sms_messaging",
"page": 1,
"per_page": 10,
"total": 1417,
"companies": [
{
"domain": "notify-hq.com",
"confidence": "vendor_keyword",
"evidence": {
"source": "https://notify-hq.com/legal/subprocessors",
"quote": "Twilio Inc. — SMS and voice message delivery"
},
"scanned_at": "2026-07-21T09:14:02Z"
},
{ "domain": "shipfast.io", "confidence": "vendor", "evidence": { "...": "..." } }
],
"credits_used": 1,
"credit_balance": 22
}- ›Each page of 10 entities costs 1 credit. Page numbering starts at 1.
Account
/v1/balanceCurrent credit balance and lifetime usage for the calling key.
| Parameter | In | Required | Description |
|---|---|---|---|
| Authorization | header | required | Bearer vr_live_… API key. |
curl "https://vendorradar-production.up.railway.app /v1/balance" \ -H "Authorization: Bearer $VENDORSTACKS_KEY"
const res = await fetch("https://vendorradar-production.up.railway.app
/v1/balance", {
headers: { Authorization: `Bearer ${process.env.VENDORSTACKS_KEY}` },
});
const { credit_balance } = await res.json();HTTP/1.1 200 OK
{
"credit_balance": 22,
"free_tier": true,
"lifetime_credits_used": 3,
"topup_url": "https://vendorstacks.com/pricing"
}Reference
/v1/pricingMachine-readable pricing: operation costs and available credit packs. Point your agent here before it spends.
curl "https://vendorradar-production.up.railway.app /v1/pricing"
const res = await fetch("https://vendorradar-production.up.railway.app
/v1/pricing");
const { operations, packs } = await res.json();HTTP/1.1 200 OK
{
"operations": {
"lookup": { "credits": 1, "note": "flat; live-scans automatically when unindexed" },
"prospect_page": { "credits": 1, "note": "per page of 10 entities" }
},
"packs": [
{ "usd": 10, "credits": 1100 },
{ "usd": 50, "credits": 6000 },
{ "usd": 250, "credits": 35000 }
],
"free_tier": { "credits": 25, "live_scans_per_day": 5 }
}/v1/vendorsThe vendor taxonomy: all 13 categories and the canonical vendor slugs recognized in each, for building reverse-lookup queries.
curl "https://vendorradar-production.up.railway.app /v1/vendors"
const res = await fetch("https://vendorradar-production.up.railway.app
/v1/vendors");
const { categories } = await res.json();
// categories.sms_messaging -> ["twilio", "sinch", ...]HTTP/1.1 200 OK
{
"categories": {
"sms_messaging": ["twilio", "sinch", "messagebird", "vonage", "plivo"],
"email": ["sendgrid", "mailgun", "postmark", "ses", "iterable"],
"payments": ["stripe", "adyen", "braintree", "checkout_com"],
"...": ["..."]
}
}/healthzLiveness probe. Returns 200 when the API is up. No auth, never rate limited.
curl https://vendorradar-production.up.railway.app /healthz
HTTP/1.1 200 OK
{ "ok": true }Confidence tiers
Every match carries a confidence field describing how the vendor was identified. Extraction is deterministic — tiers describe evidence strength, not model certainty.
| Tier | Strength | Meaning |
|---|---|---|
| vendor_keyword | Strongest | The disclosure row names the vendor and describes the matching category function (e.g. “Twilio Inc. — SMS delivery”). Both signals present in the quoted text. |
| vendor | Strong | The disclosure row names the vendor; the category is assigned from the vendor's canonical classification rather than the row's own wording. |
| vendor_inferred_sms | Inferred | No explicit SMS vendor row, but the disclosure's wording indicates SMS capability (e.g. a messaging aggregator listed for “customer communications”). Only used for the sends_sms flag, never for vendor_stack entries. |
found: false means no disclosure page could be located — not that the entity uses no vendors.
Errors at a glance
| Status | Meaning | Charged |
|---|---|---|
| 400 | validation error | No |
| 401 | unauthorized (bad or revoked key) | No |
| 402 | payment_required — includes topup_url | No |
| 404 | not_found | No |
| 413 | payload_too_large (32KB body cap) | No |
| 429 | rate_limited (rpm) or daily_scan_limit (free plan, 5 live scans/day) | No |
| 500 | internal_error — quote X-Request-Id | No |
| 502 | scan_failed — fairness rule, charged 0 | No |
Full anatomy, example bodies, and agent-handoff guidance: Documentation → Errors.