v1API Reference · base URL https://api.intentiq.dev/v1 · 99.97% uptime over 90d
✦Developers · API v1
One endpoint. Any company. 3 seconds.
POST a domain — get back a 0–100 score, the five signals it was built from, a human‑readable action, and an AI summary. Score 1,000 companies in a single bulk job. Subscribe to events with webhooks.
P50 latency
412ms
P99 latency
2.84s
Uptime · 90d
99.97%
Cache hit
71%
Quickstart
Get a real score back in under a minute. You'll need an API key (Settings → Developers) and a domain you want to score. Everything else is a single POST.
1. Get an API key
Open Settings → Developers and click Create key. Keys are shown once on creation, then stored as SHA‑256 hashes on our side — copy it into your secret manager. Test‑mode and live keys are separate: test keys are prefixed iiq_test_ and don't deduct credits.
2. Score your first account
Pick a domain. We'll fetch the five signals (funding, hiring, news, tech stack, web), compute a score, and write back an AI summary. Cold‑cache scores take ~1.4s; warm‑cache reads return in <200ms.
Domains, not URLs. Send stripe.com, not https://www.stripe.com/atlas. We'll strip schemes and subdomains for you, but apex domain is the canonical form.
3. Hook it up
For real‑time pipelines, subscribe to the score.computed webhook and let VesperWise push deltas to you. For batch enrichment, queue a bulk job and poll its status.
Authentication
All requests are authenticated with a bearer token in the Authorization header. Keys are tied to a workspace, not a user — rotate them when seat holders leave.
Header format
Pass the key as Authorization: Bearer <key>. Keys never appear in URL parameters; never log them. Workspace ID is inferred from the key.
Test vs live mode
Test keys return synthetic but plausible scores against a fixed set of well‑known domains. They never call upstream vendors, never deduct credits, and never fire webhooks. Test responses include "mode": "test" at the top level.
Rotation & revocation
Create the new key, deploy it, then revoke the old one — zero downtime. Revoked keys 401 within ~5 seconds. We also auto‑revoke a key if we detect leakage on GitHub or a public paste.
Errors
Standard HTTP status codes. The body is always JSON with a type, a stable code, and a human message. We never leak credentials, request bodies, or stack traces.
400invalid_request
The request was malformed — usually a missing field or a bad domain. The field property tells you which.
401unauthorized
Key missing, malformed, or revoked. Don't retry — fix the key first.
402insufficient_credits
Out of credits for the cycle. The resets_at field tells you when the next cycle begins.
403restricted_use
Returned when scoring inputs trigger our AUP filter (special‑category data, prohibited verticals).
404not_found
No object with that ID exists in your workspace. IDs are namespaced (scr_, job_, wl_).
409idempotency_conflict
You reused an Idempotency-Key with a different request body within the 24h window.
422unscorable_domain
Domain resolves but has no usable signal surface — parked, defunct, or no public presence. Returns score null.
429rate_limited
Back off and retry. The Retry-After header gives you the seconds to wait.
Retry policy
Retry idempotent requests with exponential backoff: 1s, 2s, 4s, 8s — five attempts max. 5xx and 429 should retry; 4xx (except 429) should not.
Rate limits
Limits are per workspace, applied at the edge. If you're hitting them, you almost certainly want the bulk endpoint instead of a tight loop.
Scoring · singlePOST /v1/score
60 req/min on Starter, 300 req/min on Team, 1,200 req/min on Scale. Per‑workspace, sliding window.
Scoring · bulkPOST /v1/score/bulk
10 concurrent jobs per workspace; up to 1,000 domains per job. Jobs over 100 domains are eligible for our overnight cache window (50% credit discount).
ReadsGET *
600 req/min on all plans. Cache‑backed; cheap.
Webhooks · deliveryoutgoing
Up to 10,000 events/hour outbound to your endpoint. We retry failed deliveries 8 times over 24 hours with exponential backoff.
Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers.
Pagination
Cursor‑based on all list endpoints. Pass limit (max 100, default 20) and cursor (from the previous response's next_cursor).
dataarray
The objects on this page, ordered by created_at descending.
has_moreboolean
True if more results are available — fetch the next page with next_cursor.
next_cursorstring · nullable
null when there are no more results.
Idempotency
All write endpoints accept an Idempotency-Key header. We store the response for 24 hours and replay it on conflict — safe to retry on flaky networks.
Use any unique string up to 255 chars (UUIDv4 is fine). If you reuse a key with a different body within the window, you get a 409 idempotency_conflict. Replays return the original response with an Idempotency-Replayed: true header.
POST/v1/scoreScore an account
Compute a fresh score for a domain. If we have a non‑stale cached score (younger than 7 days by default), we return it without deducting a credit — set force_refresh: true to bypass.
1–1,000 apex domains. Duplicates are collapsed before billing.
deferredoptionalboolean
If true, runs in our overnight cache window for a 50% credit discount. Results return within 8 hours.
Default: false
webhook_urloptionalstring
POST target for the score.bulk.completed event. We sign the payload — see verify signatures.
tagoptionalstring
Free‑form label echoed back in webhook payloads — useful for correlating with your queue.
POST/v1/people/scoreScore a person
Score the human behind the logo. Provide an email or a LinkedIn URL — we enrich via Apollo with PDL fallback, then layer the underlying account's intent on top.
200 ok422 unresolvable_person403 restricted_use
Body parameters
emailone ofstring
Work email. Free‑mail providers (Gmail, etc) return 422 unresolvable_person.
linkedin_urlone ofstring
Canonical LinkedIn profile URL — must include the /in/ path segment.
role_hintoptionalstring
Disambiguator when a name resolves to multiple people. Examples: "RevOps", "Founder".
GET/v1/watchlistsList watchlists
Paginated list of watchlists in your workspace, ordered by most recently updated. Each entry includes a count of accounts and the current band distribution.
200 ok
Query parameters
limitoptionalinteger · 1–100
Page size.
Default: 20
cursoroptionalstring
Pagination cursor from the previous response.
POST/v1/watchlistsCreate a watchlist
Pin up to 250 accounts (Starter), 1,000 (Team), or 10,000 (Scale). The moment any account crosses your band threshold, we fire account.band_changed.
Body parameters
namerequiredstring
Display name. Max 80 chars.
accountsoptionalarray<string>
Initial set of domains. Same as calling PUT /accounts after create.
alert_thresholdoptionalenum
When to fire account.band_changed.
"hot_entry" (default)
"any_band_change"
"score_delta_10"
PUT/v1/watchlists/{id}/accountsAdd accounts to a watchlist
Idempotent — adding a domain that's already on the list is a no‑op, not an error. Returns the full updated account list.
DELETE/v1/watchlists/{id}/accountsRemove accounts from a watchlist
Removes the domains in accounts from the watchlist. Does not delete the underlying score history.
Webhooks
We POST events to your endpoint as JSON. Deliveries are signed (HMAC‑SHA256), at‑least‑once, and retried on non‑2xx with exponential backoff for 24 hours. Subscribe in Settings → Webhooks.
Delivery contract
Respond 2xx within 5 seconds — do the work asynchronously. We send User-Agent: VesperWise-Webhook/1.0 and a X-IIQ-Signature header you should verify. Events carry a delivery_attempt integer so you can dedupe.
Local development. Point a webhook at the VesperWise CLI (iiq webhooks listen) — it tunnels deliveries to http://localhost:3000/webhooks without ngrok.
Event types
score.computed
Fires every time a score is computed — both fresh cold‑cache misses and forced refreshes. The most common event in the system.
~6/sec p50
score.bulk.completed
Fires when a bulk job finishes. Payload includes the full result array and any unscorable domains separated out.
on demand
account.band_changed
A watchlist account crossed a band threshold (e.g. WARM → HOT). The flagship "now is the time" event for sales workflows.
~40/day p50
signal.spike
A single signal (e.g. funding) for a watchlist account jumped >25 points week‑over‑week. Often precedes a band change by 24–48h.
~12/day p50
person.scored
A previously unknown person was successfully resolved and scored. Pair with your CRM enrichment flow.
on demand
credits.low
Your workspace dropped below 10% of the cycle's credit allocation. Fired once per cycle.
Every delivery includes X-IIQ-Signature: t=<timestamp>, v1=<hmac>. Reject any request where the timestamp is older than 5 minutes (replay protection) and the HMAC does not validate against your signing secret.
The signing secret is shown once when you create the webhook endpoint, then stored hashed on our side — rotate it from the Webhooks settings page. The signed payload is the raw request body, not the parsed JSON.
The Score object
The canonical response shape. Returned by POST /v1/score, GET /v1/score/{id}, and nested inside score.computed webhooks.
idstring
Stable score ID. Prefixed scr_.
domainstring
Apex domain, lower‑cased.
scoreinteger · 0–100, nullable
null on unscorable domains (use the band field, which will also be null).
bandenum
One of "HOT" (≥80), "WARM" (60–79), "COLD" (<60), or null.
delta_30dinteger
Change in score vs 30 days ago. Positive means rising.
signalsobject
The five underlying signals, each 0–100. See Signal for shape.
actionstring
AI‑generated one‑sentence recommended action. Never empty; never longer than 140 chars.
summarystring · markdown
3–5 sentence AI summary. Markdown limited to **bold** and links.
cachedboolean
true if served from cache; false if computed fresh.
computed_attimestamp · ISO 8601
When the underlying signals were last refreshed.
The Signal object
Each of the five signals is returned as a nested object inside signals when you request include=signals.evidence.
scoreinteger · 0–100
Weighted sub‑score for this signal. Rolled up into the composite intent score.
evidencearray
Raw observations backing the score — funding rounds, job titles, news headlines, etc.
sourcestring
Upstream vendor that provided the data.
fetched_attimestamp · ISO 8601
When this signal was last fetched from its source.
The Person object
Returned by POST /v1/people/score and in person.scored webhook payloads.
idstring
Stable person ID. Prefixed prs_.
namestring
Full name as resolved from the enrichment provider.
emailstring
Work email. May differ from the input if resolved via LinkedIn.
titlestring
Current job title at the resolved company.
companystring
Company domain. Use this to retrieve the underlying Score object.
intent_scoreinteger · 0–100
The underlying company intent score at resolution time.
seniorityenum
One of "ic", "manager", "director", "vp", "c_level".
resolved_attimestamp · ISO 8601
When this person was last enriched.
Official SDKs
Thin wrappers around the REST API with retry/backoff, typed responses, and idiomatic ergonomics. Source on GitHub; bug reports welcome.
Node / TypeScript@vesperwise/node
Node 18+, fully typed. npm i @vesperwise/node.
Pythonintentiq
Python 3.10+, sync and async clients. pip install intentiq.
Gogithub.com/intentiq/go-sdk
Go 1.21+, context‑aware, zero deps outside stdlib + x/sync.
CommunityRuby · PHP · Elixir
Maintained by customers. Listed on our community SDKs page; we don't guarantee parity.
API changelog
We version the API by URL prefix (currently /v1). Breaking changes ship under a new version with at least 12 months of overlap. Additive changes ship anytime.
2026‑05‑12additive
Added include=people expansion on POST /v1/score. Added signal.spike webhook event.
2026‑03‑04additive
deferred option on bulk jobs (50% credit discount, 8h SLA). New credits.low webhook.
2026‑01‑22behavior
Default cache freshness moved from 14d to 7d across all plans. X-IIQ-Cache response header added.
2025‑11‑08v1 stable
API marked stable; SLAs in effect. Frozen surface area for the next 12 months.