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.

200 ok422 unscorable_domain402 insufficient_credits429 rate_limited

Body parameters

domainrequiredstring
Apex domain to score. Subdomains and protocols are stripped.
Example: stripe.com
force_refreshoptionalboolean
Skip cache and recompute from upstream signal vendors. Always deducts a credit.
Default: false
includeoptionalarray<string>
Optional response expansions.
  • "signals.evidence" — raw signal observations
  • "history" — last 30 score values
  • "people" — top 5 contacts by score
webhook_urloptionalstring
For cold‑cache misses exceeding 3s, return 202 immediately and POST the result to this URL when ready.

Returns

A Score object. The HTTP response also carries X-IIQ-Cache: hit|miss|refresh for billing attribution.

Request
curl -X POST https://api.intentiq.dev/v1/score  \
  -H "Authorization: Bearer $IIQ_KEY"  \
  -H "Content-Type: application/json"  \
  -d '{ "domain": "stripe.com" }'
200 OK · POST /v1/score1.42s · cache miss
{
  "id": "scr_01HZ9X3F7QMHN4T",
  "domain": "stripe.com",
  "score": 94,
  "band": "HOT",
  "delta_30d": +12,
  "signals": {
    "funding": 96,
    "hiring":  88,
    "news":    92,
    "tech":    78,
    "web":     84
  },
  "action": "Reference Series H. Anchor on RevOps.",
  "summary": "Stripe is showing fresh capital, aggressive RevOps hiring...",
  "cached": false,
  "computed_at": "2026-05-28T14:02:11Z"
}

GET/v1/score/{id}Retrieve a score

Look up a previously computed score by its scr_ ID. Never deducts a credit. Returns the most recent score for the underlying domain.

200 ok404 not_found

Path parameters

idrequiredstring
The score ID, e.g. scr_01HZ9X3F7QMHN4T. Returned by POST /v1/score and in every webhook payload.

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.

202 accepted400 invalid_request402 insufficient_credits

Body parameters

domainsrequiredarray<string>
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.
≤1/month
Webhook
{
  "id":       "evt_01HZ9X3FK8M2P",
  "type":     "score.computed",
  "created":  "2026-05-28T14:02:11Z",
  "data": {
    "score": { /* Score object */ },
    "trigger": "watchlist_refresh"
  },
  "delivery_attempt": 1
}
POST → your.app/iiqX-IIQ-Signature: t=…,v1=…

Verify webhook signatures

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.
Questions? developers@intentiq.dev