Build on the industry’s connection graph
Key-gated, contact-free read access to the verified company, games and regulatory catalog — plus signed webhooks when the data changes. The same provenance-backed facts that power Vunk, available to your systems.
Base URL https://bevunk.com/v1/public
Authentication
Every request needs an API key. A company owner or admin issues keys for their company. The full secret (vunk_sk_…) is shown exactly once at creation — store it securely; we keep only a hash. Send it in the X-API-Key header, or as a Bearer token.
curl https://bevunk.com/v1/public/companies \ -H "X-API-Key: $VUNK_API_KEY" # or, equivalently curl https://bevunk.com/v1/public/companies \ -H "Authorization: Bearer $VUNK_API_KEY"
Scopes
Each key carries one or more scopes; a request to a surface outside the key’s scopes returns 403.
catalog:readCompanies and games — /v1/public/companies, /v1/public/gamesregulatory:readJurisdictions and regulatory changes — /v1/public/jurisdictions
Rate limits are per key. Exceeding your budget returns 429 with a Retry-After header. Contacts are never included in any response.
Read endpoints
Cursor-paginated lists and slug detail. Lists accept limit and an opaque cursor; responses carry a next_cursor (null on the last page).
GET /v1/public/companies?limit=20&cursor=... # scope: catalog:read
GET /v1/public/companies/:slug
GET /v1/public/games?limit=20 # scope: catalog:read
GET /v1/public/games/:slug
GET /v1/public/jurisdictions?limit=20 # scope: regulatory:read
GET /v1/public/jurisdictions/:slug
# example response shape
{
"items": [ { "slug": "...", "name": "...", "verified": true, "...": "..." } ],
"next_cursor": "eyJrIjoi..."
}Every fact carries provenance (source, confidence, last verified). Below the freshness threshold, data is excluded — by charter, stale data is never served.
Versioning, embeds & fair use
Every response carries an X-API-Version header and a Link: </developers>; rel="service-doc". When an endpoint is scheduled for retirement, its responses add the IETF deprecation headers so your client can detect it automatically — at least 90 days before it stops working:
Deprecation: true Sunset: Wed, 01 Jan 2027 00:00:00 GMT Link: </developers#deprecation>; rel="deprecation"
Embed a status badge
Show your verified status anywhere with a cacheable SVG badge — no key required:
<img src="https://bevunk.com/v1/public/embed/companies/YOUR-SLUG/badge.svg"
alt="Status on Vunk" height="20">Fair use & data canaries
The catalog is free to read but not to re-publish wholesale. Key-gated responses carry a per-key X-Vunk-Trace watermark; if exported data resurfaces elsewhere it identifies the source key. Don’t resell the raw dataset, and cache responsibly — there are no contacts in the API to scrape, by design.
Webhooks
Register an HTTPS endpoint to receive a signed POST when catalog or regulatory data changes — no polling. The signing secret is shown once at registration. Vunk retries with exponential backoff and auto-disables an endpoint after sustained failures.
Events
company.verifiedA company reached a new KYB verification level.company.listing_status.changedA company’s earned standing changed.game.releasedA game hit a launch or market-launch milestone.jurisdiction.change.publishedA regulatory change was published for a jurisdiction.
Verifying the signature
Each delivery carries an X-Vunk-Signature header of the form t=<unix>,v1=<hex>, where v1 is the HMAC-SHA256 of "<t>.<raw-body>" keyed by your signing secret. Compare in constant time and bound the timestamp to reject replays.
import crypto from "node:crypto";
function verify(secret, header, rawBody) {
const [t, v1] = header.split(",").map((p) => p.split("=")[1]);
const expected = crypto
.createHmac("sha256", secret)
.update(t + "." + rawBody)
.digest("hex");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(v1, "hex");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Payloads carry only public identifiers (ids, slugs) — fetch the full record from the read API. Headers also include X-Vunk-Event and X-Vunk-Delivery (dedupe on the latter).
Errors
One JSON shape for every error — no stacks, no internals. Status codes: 401 (no/invalid key), 403 (missing scope), 404, 429 (rate limited).
{ "error": { "code": "unauthorized", "message": "API key required",
"requestId": "01H...", "details": { "header": "X-API-Key" } } }Get a key
Access is invite-only while we onboard founding companies. A company owner or admin issues API keys from the company account.