v1API Reference · base URL https://api.intentiq.dev/v1 · 99.97% uptime over 90d
✦Developers · API v1
One endpoint. Any company. Explicit coverage.
POST a domain — get back a coverage-aware 0–100 score, four dated intent triggers, account context, an action, and an AI summary. Scores below 60% reliable trigger coverage return 422 with a null score.
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 four intent triggers (funding, hiring, non-funding news, and dated technology changes), collect Web and GitHub context, compute coverage, and write back an AI summary. A personalized six-hour cache makes repeat scores free.
Use the apex domain. Send stripe.com. Schemes, paths, and a leading www. are normalized, but arbitrary subdomains are not guessed back to an apex.
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, or the same score run is still in progress.
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
POST /v1/score accepts an Idempotency-Key header. The key is atomically bound to its request and completed response, so retries cannot double-charge.
Use any unique string up to 255 chars (UUIDv4 is fine). Reusing a key with a different request returns 409 idempotency_conflict. Completed replays return the original response with an Idempotency-Replayed: true header.
POST/v1/scoreScore an account
Compute or retrieve a personalized score for a domain. Results are cached for six hours by user, canonical domain, profile fingerprint, and scoring version; cache hits are free.
Apex domain to score. Schemes, paths, and a leading www. are normalized.
Example: stripe.com
companyoptionalstring
A display name for the response and reasoning. Provider evidence is always resolved and cached by canonical domain, not this caller-supplied label.
Optional header
Send Idempotency-Key: <unique value> to make retries exact-once. The endpoint accepts keys up to 255 characters.
Returns
A Score object. The HTTP response also carries X-IIQ-Cache: hit|miss for billing attribution. Unscorable domains return 422, intent_score: null, and are not charged or written to score history.
Legacy GET wrapper over the same scoring service as POST. It uses the same cache, exact-once charging, coverage rules, and response shape. New integrations should use POST.
200 ok422 unscorable_domain
Query parameters
domainoptionalstring
The canonical company domain. Recommended for reliable matching.
companyoptionalstring
Compatibility fallback when no domain is supplied. We derive a best-effort .com domain, so explicit domain is safer.
POST/v1/score/bulkBulk score job
Submit up to 1,000 domains per job. Returns a job_ ID you can poll, or supply a webhook_url and we'll POST score.bulk.completed when the run finishes.
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 scoring-v2 response shape returned by POST /v1/score and its GET compatibility wrapper.
score_idstring
Stable persisted score ID on scorable results.
domainstring
Apex domain, lower‑cased.
intent_scoreinteger · 0–100, nullable
null when eligible trigger coverage is below 60%.
score_bandenum
One of "HOT" (≥75), "WARM" (50–74), "COLD" (<50), or null.
score_statusenum
complete, partial, or unscorable.
data_coveragenumber · 0–1
Eligible trigger weight divided by total trigger weight. Stale last-known-good evidence contributes half weight.
scoring_versionstring
v2-linear-2026-07 for the new linear model.
icp_fit_scoreinteger · 0–100, nullable
Separate fit score from verified industry (60%) and employee-range alignment (40%).
signalsobject
Four scored triggers plus Web and GitHub context. See Signal for shape.
contributionsarray
Auditable base/effective weight, normalized value, freshness, and contribution for each intent trigger.
recommended_actionstring
Schema-validated recommended action, with a deterministic fallback if the AI call fails.
ai_summarystring
Bounded score reasoning, with deterministic fallback.
cachedboolean
true if served from cache; false if computed fresh.
chargedboolean
true only when this request atomically consumed a credit.
The Signal object
Funding, Hiring, News, Technology, Web, and GitHub are returned inside signals. Only the first four can contribute to intent_score; Web and GitHub are context only.
scorenumber
Raw provider score, normalized against max before freshness and weighting.
statusenum
ok, no_signal, not_found, stale, or unavailable.
observed_attimestamp · nullable
Actual event date used for freshness. Positive v2 evidence without a valid date cannot contribute.
evidencearray
Structured observations backing the signal, including source metadata.
sourcestring
Upstream vendor that provided the data.
fetched_attimestamp · ISO 8601
When this signal was last fetched from its source.
source_urlURL · optional
Source page for an individual evidence item, when available.
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.