Find the company behind a visit.
Look up an IP you already have, or install a website pixel and choose which visits to identify.
- IP lookupSend an IPv4 or IPv6 address. Get saved company or network details, or request enrichment when needed.
- Website pixelsCreate a tracker per customer website. Use our domain or connect your own.
- Preview, then revealSee a session’s estimated country first. Request company or network details only for the sessions you choose.
- Custom labelsAttach your customer ID, campaign or other labels. They travel with the session, reveal and webhook.
- WebhooksReceive signed events for new sessions and completed reveals. Check deliveries and retry failures.
- Usage & controlsCheck requests, outcomes, reveal units and limits. Read usage per tracker; enable, disable or delete pixels.
- Partner dashboardSign in to see your account, API keys, pixels and usage, and manage webhooks.
Pixel flow: Install → Preview country → Choose a session → Reveal.
Each new reveal with company or network data uses one unit, including ISP and cached results. Previewing adds no reveal unit; retrying the same reveal adds no extra unit.
Use an API key from your server; never put it in the pixel. 202 means processing—follow Retry-After and poll. A company match is not guaranteed. OpenAPI · AI agent guide
Look up a company by IP address
Enter an IP address to find its company. Paste your key below to try it.
Try a request 1. Key → 2. Parameters → 3. Send
Send a real request to https://partner.rktad.com.
See the country. Choose what to reveal.
Give each customer a tracker. Read visitor countries first, then request company or network data only for the sessions you choose.
- InstallCreate a tracker. Copy its script to the website.
- PreviewRead new sessions and their visitor countries.
- RevealChoose a session and request its details.
What goes on the website?
<script async src="https://partner.rktad.com/tracking/a.js?tracker_id=YOUR_TRACKER_ID"></script>
Use the exact snippet returned by POST /v1/trackers. Add your own labels with data-custom; they appear in sessions, reveals and webhooks. Your API key stays on your server. Use your own domain →
GET /tracking/a.js loads the pixel. It sends visits to POST /tracking/collect automatically. It does not read forms or email fields.
Sessions, privacy and limits
This tracker collects IP and estimated country, public tracker/session tokens, visit times and any custom labels you explicitly supply. It does not read forms, emails or page contents. It uses first-party session storage for a per-tab visit token, renewed after 30 minutes without a tracked visit. Without storage, page reloads can create extra sessions. An IP or country change creates a separate session.
Follow your site’s consent requirements before loading the script. Sessions and receipt results are accessible for 30 days; billing counts remain. Country filtering happens in your app. A skipped session does not trigger new enrichment. The feed reports new sessions, not every page view.
Initial tracking limits: 200 capture requests/sec total, 100/sec per tracker, 10/sec per visitor IP. New reveal creation: 100/sec per partner, within the API key’s request limit. New enrichment shares the existing 900/minute intake and pending limits. These are admission limits, not a performance guarantee. Browser blocking, network failures and these limits can prevent collection.
Country is approximate and can reflect a VPN. IP Geolocation by DB-IP, September 2026 Lite data, CC BY 4.0. Applications displaying or using this country data must preserve the required attribution.
/v1/trackersCreate a website trackerTry →GET/v1/trackersList your website trackersTry →GET/v1/sessionsPreview new sessions and visitor countriesTry →GET/v1/sessions/{session_id}Read a session previewTry →POST/v1/sessions/{session_id}/revealReveal company or network informationTry →GET/v1/reveals/{reveal_id}Read or poll an existing revealTry →DELETE/v1/trackers/{tracker_id}Disable a trackerTry →POST/v1/trackers/{tracker_id}/enableEnable a trackerTry →POST/v1/trackers/{tracker_id}/deletePermanently delete a trackerTry →GET/v1/trackers/{tracker_id}/usageRead usage for one trackerTry →One new reveal with data = one billable unit. Includes ISP and cached data. Previewing, retrying the same reveal and polling add no extra unit. 202 means wait, then poll the receipt. Check reveal usage →
Send custom pixel parameters
Add your own labels with data-custom. They are saved from the first accepted visit in each session and returned as custom in session previews, reveal receipts and both webhook events. Later visits update last_seen_at, but do not replace these labels. Missing values and older sessions return {}.
<script async
src="https://partner.rktad.com/tracking/a.js?tracker_id=YOUR_TRACKER_ID"
data-custom='{"account_id":"acme","campaign":"autumn","plan":"pro"}'></script>Dynamic JavaScript values
const pixel = document.createElement('script');
pixel.async = true;
pixel.src = 'https://partner.rktad.com/tracking/a.js?tracker_id=YOUR_TRACKER_ID';
pixel.dataset.custom = JSON.stringify({account_id: 'acme', campaign: 'autumn'});
document.head.appendChild(pixel);Use a flat JSON object: up to 32 fields and 2,048 UTF-8 bytes total. Values may be strings (up to 512 characters), numbers, booleans or null. No arrays or nested objects. Field names must start with a letter and contain only letters, digits, underscores, dots or hyphens (up to 64 characters); constructor and prototype are reserved. Invalid data-custom stops that pixel execution and logs a browser warning. Invalid direct capture requests return 400 invalid_custom_parameters.
These labels are supplied by the website and can be changed by a visitor. Use them for context, never for access control, trusted account ownership or billing. Keep API keys, passwords and personal data out of the snippet. Use non-sensitive internal references. HTML-escape dynamic attribute values, or use the JavaScript example with dataset.custom.
Use your own tracker domain
Send us your hostname, such as track.yourcompany.com. Create a DNS-only CNAME to partner.rktad.com. Wait for us to activate HTTPS and assign it to your account, then use your returned snippet. Allow that hostname in your website’s script-src and connect-src policies.
Webhooks: events, signatures and delivery
Register your receiver before installing the pixel. Check the country in session.created, explicitly request a reveal, then receive reveal.completed.
curl https://partner.rktad.com/v1/webhooks \
-H "Authorization: Bearer $PARTNER_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"name":"Production","url":"https://your-app.example/webhooks","events":["session.created","reveal.completed"]}'Session event example
{
"id": "evt_session_00000000-0000-4000-8000-000000000001",
"type": "session.created",
"schema_version": 1,
"created_at": "2026-09-25T12:00:00.000Z",
"data": {
"session_id": "00000000-0000-4000-8000-000000000001",
"tracker_id": "00000000-0000-4000-8000-000000000002",
"customer_reference": "acme",
"custom": {
"account_id": "acme",
"campaign": "autumn",
"plan": "pro"
},
"visitor_country": "GB",
"first_seen_at": "2026-09-25T12:00:00.000Z",
"last_seen_at": "2026-09-25T12:00:00.000Z",
"expires_at": "2026-10-25T12:00:00.000Z"
}
}Completed reveal example
{
"id": "evt_reveal_00000000-0000-4000-8000-000000000003",
"type": "reveal.completed",
"schema_version": 1,
"created_at": "2026-09-25T12:00:00.000Z",
"data": {
"reveal_id": "00000000-0000-4000-8000-000000000003",
"session_id": "00000000-0000-4000-8000-000000000001",
"tracker_id": "00000000-0000-4000-8000-000000000002",
"custom": {
"account_id": "acme",
"campaign": "autumn",
"plan": "pro"
},
"status": "complete",
"billable": true,
"billable_units": 1,
"created_at": "2026-09-25T12:00:00.000Z",
"completed_at": "2026-09-25T12:00:00.000Z",
"expires_at": "2026-10-25T12:00:00.000Z",
"result": {
"status": "complete",
"match_type": "company",
"company_found": true,
"enriched_at": "2026-09-18T12:00:00.000Z",
"stale": false,
"fresh_until": "2026-10-18T12:00:00.000Z",
"refresh_status": "not_needed",
"refresh_error": null,
"network": {
"connection_type": "Business",
"audience_type": "Business",
"audience_group": null,
"detail_level": null,
"is_isp": false
},
"company": {
"name": "Example Company",
"website": "example.com",
"brand_name": null,
"linkedin_url": null,
"industry": "Software",
"industry_subcategory": null,
"employees": "120",
"annual_revenue": null,
"revenue_band": null,
"naics_code": "541511",
"sic_code": null,
"city": "London",
"region": null,
"postal_code": null,
"country_code": "GB",
"country_name": "United Kingdom"
}
},
"status_url": "/v1/reveals/00000000-0000-4000-8000-000000000003"
}
}Verify signatures against the exact raw body. Save the event durably before returning 2xx, and deduplicate by event ID. Delivery is at least once and may be out of order. Retry attempts do not add reveal units.
Verify every delivery
Headers: webhook-id, webhook-timestamp (Unix seconds), webhook-signature.
Signature: v1,BASE64_HMAC_SHA256. During secret rotation the header contains two space-separated signatures. Decode the base64 after whsec_ to get the signing key. Sign the exact string ID.TIMESTAMP.RAW_BODY. Do not parse and reserialize JSON before verification. Check a five-minute timestamp window and use a constant-time comparison. Treat malformed or duplicate headers as invalid. Keep your server clock synchronized.
import {createHmac, timingSafeEqual} from 'node:crypto';
function verifyWebhook(rawBody, headers, secret) {
const id = headers['webhook-id'];
const timestamp = headers['webhook-timestamp'];
const signatures = headers['webhook-signature'];
if (typeof id !== 'string' || !/^evt_[a-zA-Z0-9_-]{1,100}$/.test(id) ||
typeof timestamp !== 'string' || !/^\d{10,11}$/.test(timestamp) ||
Math.abs(Date.now() / 1000 - Number(timestamp)) > 300 ||
typeof signatures !== 'string' || signatures.length > 512) return false;
const expected = createHmac('sha256', Buffer.from(secret.slice(6), 'base64'))
.update(id + '.' + timestamp + '.').update(rawBody).digest();
return signatures.split(' ').some(part => {
if (!/^v1,[A-Za-z0-9+/]{43}=$/.test(part)) return false;
const actual = Buffer.from(part.slice(3), 'base64');
return actual.length === expected.length && timingSafeEqual(actual, expected);
});
}Enforce a bounded receiver body limit (1MiB is sufficient for current event payloads). After verification, check event.id equals webhook-id. Atomically store the event and its ID in your own durable queue, then return 200 or204 promptly. Return2xx for an already stored duplicate too. Process business logic asynchronously. Never trust webhook payloads without signature validation.
Delivery guarantees and retries
At least once, not exactly once. Events may arrive more than once or out of order. Deduplicate by event.id, not session ID: a session can have multiple separately billed reveals. Retries and manual redelivery preserve event ID and payload; timestamp and signature are refreshed for each attempt. A timeout after your server stored the event can cause another delivery.
Public HTTPS port443 only. TLS certificates must be valid. Private/loopback/link-local/reserved addresses, this platform's origin, mixed public/private DNS answers and redirects are rejected. All destination IPs are checked on every attempt. No receiver response body is retained.
Any2xx acknowledges. Other HTTP statuses, DNS/TLS/connect errors and10-second timeouts retry with exponential delay (about15seconds initially, capped at6hours, with jitter). Retry-After is respected up to24hours. After12 attempts or7days per retry cycle, failed deliveries stay visible. Manual retry starts another cycle while the source payload remains available. Pending includes retrying, paused and in-flight deliveries. Failed, expired and cancelled are separate states.
Payloads expire with their session or receipt, at most30days from session creation. A late reveal may have less time left. Expired payloads cannot be replayed; minimal delivery metadata remains90days. Operational cleanup is incremental. One endpoint may have up to32 concurrent deliveries and200 delivery starts/second; these are ceilings, not guaranteed throughput. Slow receivers reduce delivery speed. Queue capacity is2,500,000 pending deliveries per partner. A shared retained-payload storage limit can also temporarily stop new events; each event is limited to1MiB. When full, source capture/reveal completion is rejected with503 and is not acknowledged as successful; retry safely. A queued accepted reveal remains pending until completion can commit. Pause does not free queue slots.
POST /v1/webhooks/{id}/rotate-secret with {} returns a new signing_secret once. Both signatures are sent for24hours, then only the new one. A second rotation during this overlap returns409. On a lost rotation response, use the existing secret during the overlap, then rotate again after the overlap; inspect secret_rotation_until and do not assume the lost new secret can be recovered.
Errors and accounting
400 invalid_webhook / invalid_webhook_url / invalid_webhook_query: fix request.
401 unauthorized: check API key.
404 webhook_not_found / webhook_delivery_not_found / tracker_not_found: wrong ID or account.
409 webhook_disabled / webhook_rotation_pending: enable endpoint or wait for overlap.
410 webhook_event_expired: payload no longer available.
429 webhook_limit / webhook_management_limit / rate_limit / api_rate_limit: follow Retry-After. Management budget120/minute per partner per service, separate from lookup allowance.
503 webhook_queue_full / webhooks_unavailable / service_unavailable: retry with backoff; do not treat as delivered.
Creation, tests, delivery reads, configuration changes and redelivery do not count lookup requests or reveal units. Completing an already authorized reveal follows the existing per-reveal billing rule. Delivery success is not a condition for billing. No webhook automatically starts a new reveal.
API key & security
Get a key from your API administrator. Send it as Authorization: Bearer YOUR_API_KEY. Keep it on your server, not in a public page. A missing or invalid key returns 401.
Query parameters
ipstringrequiredUse one public IPv4 or IPv6 address, such as 8.8.8.8. Do not include a website URL or port.
Send exactly one ip query parameter. GET never starts enrichment.
fromdateoptionalInclusive start date in UTC. Defaults to today.
todateoptionalExclusive end date in UTC. Defaults to tomorrow. The range must be positive and at most 31 days.
New IP? Here’s what happens.
- POST the IP. Get a saved result now, or start a new lookup.
- 202 means wait. We’re looking it up. It does not mean “no company.”
- GET the result. Wait at least 15 seconds between checks. A new lookup may take longer.
See the flow diagram
Read the answer
company_found: true means we found a company. false means ISP or uncertain classification. Still check company: any details we have are included.
The answer is not ready. Check the returned status_url after Retry-After seconds.
404 on GET? Use POST to start the lookup. Errors are never a “no company” result.
See the result guide
Choose a response example in the tester. Examples are made up; test with a real public IP.
Errors & fixes
Check error.code below for the fix. Share request_id with support.
{
"error": {
"code": "unauthorized",
"message": "The key is missing, malformed, invalid, expired or revoked."
},
"request_id": "00000000-0000-4000-8000-000000000001"
}
58 known application codes
| HTTP / code | What happened | What to do |
|---|---|---|
400invalid_ip | The IP is missing, malformed, private or reserved. | Send one public IPv4 or IPv6 address, without a port, CIDR suffix or zone ID. |
400invalid_query | The query parameters do not match the endpoint. | GET lookup needs exactly one ip parameter. POST lookup takes JSON, with no query string. |
400invalid_json | The request body is not valid JSON. | Send valid JSON such as {"ip":"8.8.8.8"}. |
400invalid_body | The JSON body has the wrong shape or extra fields. | Send an object containing only ip. A missing or invalid ip returns invalid_ip. |
400invalid_range | The usage dates or query parameters are invalid. | Use real UTC dates, from < to, at most 31 days, with no duplicate or extra parameters. |
401unauthorized | The key is missing, malformed, invalid, expired or revoked. | Send exactly one Authorization: Bearer header with an active key. Contact your API administrator for a replacement. |
404not_requested | GET found no saved result and no API enrichment submission. | POST the same IP to request enrichment, then poll with GET. This is not a confirmed no-company result. |
404not_found | The endpoint does not exist. | Check the path. Use /v1/lookup or /v1/usage. |
405method_not_allowed | The lookup endpoint does not accept this HTTP method. | Use GET or POST; the Allow response header lists the accepted methods. |
413body_too_large | The request body exceeds 1,024 bytes. | Submit one IP per request in a small JSON object. |
414uri_too_long | The request URL exceeds 512 characters. | Shorten the path and query. Never put your API key in the URL. |
415unsupported_media_type | The POST Content-Type is not application/json. | Set Content-Type: application/json. |
415unsupported_encoding | The request has a Content-Encoding header. | Send uncompressed JSON without Content-Encoding. |
429rate_limit | This key has exceeded its request rate. | Wait at least Retry-After seconds, then reduce concurrency. View your key limits with GET /v1/usage. |
429api_rate_limit | The API has reached its shared request capacity. | Honor Retry-After, add jitter and retry with lower concurrency. |
429lookup_capacity | Too many distinct IP lookups are in flight. | Honor Retry-After and retry with fewer simultaneous lookups. |
429pending_limit | Your partner has reached its limit for unfinished enrichments. | Wait for existing lookups to finish before submitting new IPs. View enrichment and limits in GET /v1/usage. Repeating an accepted IP is allowed. |
429enrichment_limit | This key has used its daily allowance for new enrichment reservations. | Wait until the next UTC day or ask for a higher allowance. Existing saved lookups remain available; retrying every 15 seconds will not reset the allowance. |
429enrichment_capacity | The shared enrichment intake or outstanding-work limit is full. | Honor Retry-After and use backoff. Repeated submissions do not speed up the lookup. |
503api_busy | The API is temporarily busy. | Honor Retry-After (normally 5 seconds for this code) and retry with backoff. |
503backend_unavailable | The lookup or enrichment request could not be completed. | Retry with backoff. A failed POST response does not prove submission failed; repeating the same POST is safe. |
503backend_timeout | The request took too long to complete. | Retry with backoff. Do not interpret a timeout as a no-company result. |
503submission_unconfirmed | An enrichment reservation exists, but acceptance was not confirmed. | Repeat POST for the same IP to confirm submission, then poll with GET. |
503lookup_reconciliation_required | Work is marked complete, but the saved lookup is unavailable. | Retry later; if persistent, share request_id with your API administrator. |
503usage_unavailable | Usage reporting is temporarily unavailable. | Retry with backoff. A POST may already have been submitted; repeating the same IP is safe. |
503service_unavailable | An unexpected temporary service failure occurred. | Honor Retry-After and retry with backoff; share request_id if the error persists. |
400invalid_origin | invalid origin | Check the request fields and formats. |
400invalid_tracker | invalid tracker | Check the request fields and formats. |
400invalid_capture | invalid capture | Check the request fields and formats. |
400invalid_custom_parameters | invalid custom parameters | Check the request fields and formats. |
400invalid_cursor | invalid cursor | Check the request fields and formats. |
400invalid_idempotency_key | invalid idempotency key | Check the request fields and formats. |
403untrusted_collector | untrusted collector | Check the tracker origin and enabled state. |
403tracker_origin_denied | tracker origin denied | Check the tracker origin and enabled state. |
404tracker_not_found | tracker not found | Check the ID and partner account. |
404session_not_found | session not found | Check the ID and partner account. |
404reveal_not_found | reveal not found | Check the ID and partner account. |
409idempotency_conflict | idempotency conflict | Resolve the state conflict; do not create a new reveal just to retry. |
409tracker_disabled | tracker disabled | Resolve the state conflict; do not create a new reveal just to retry. |
410tracker_deleted | tracker deleted | This resource or payload is no longer available. |
410session_expired | session expired | This resource or payload is no longer available. |
410reveal_expired | reveal expired | This resource or payload is no longer available. |
429tracking_capacity | tracking capacity | Follow Retry-After and your account limits. |
429tracker_limit | tracker limit | Follow Retry-After and your account limits. |
503tracking_unavailable | tracking unavailable | Retry with backoff. Keep the same Idempotency-Key for reveal retries. |
503reveal_unconfirmed | reveal unconfirmed | Retry with backoff. Keep the same Idempotency-Key for reveal retries. |
400invalid_webhook | invalid webhook | Check the request fields and formats. |
400invalid_webhook_url | invalid webhook url | Check the request fields and formats. |
400invalid_webhook_query | invalid webhook query | Check the request fields and formats. |
404webhook_not_found | webhook not found | Check the ID and partner account. |
404webhook_delivery_not_found | webhook delivery not found | Check the ID and partner account. |
409webhook_disabled | webhook disabled | Resolve the state conflict; do not create a new reveal just to retry. |
409webhook_rotation_pending | webhook rotation pending | Resolve the state conflict; do not create a new reveal just to retry. |
410webhook_event_expired | webhook event expired | This resource or payload is no longer available. |
429webhook_limit | webhook limit | Follow Retry-After and your account limits. |
429webhook_management_limit | webhook management limit | Follow Retry-After and your account limits. |
503webhook_queue_full | webhook queue full | Retry with backoff. Keep the same Idempotency-Key for reveal retries. |
503webhooks_unavailable | webhooks unavailable | Retry with backoff. Keep the same Idempotency-Key for reveal retries. |
No matching errors. Clear your search to see the full reference.
Connection errors
A connection failure may return no JSON or request ID. Handle unexpected HTTP codes and non-JSON responses. Record the status and request ID when available, and contact support if retries fail.
If a POST times out or returns 503, the IP may already have been submitted. Repeat the same POST to confirm. Never turn a transport failure, 404 or 202 into “no company.”
Optional company clues
Some keys include company_signals: possible companies linked to recent activity on that IP. A clue is not a confirmed employer. submitted means a submit event was seen; field_only means an email was typed. Check flags before using a clue. The main company result stays separate.
No email addresses or visited pages are returned. unavailable means clues could not be checked; it does not mean there are none.
All response fields
Null means a usable value is unavailable. Do not infer a value from a missing field. Large employees and annual_revenue integers may be decimal strings to preserve precision.
Error3 fields
| Field | Type | Meaning |
|---|---|---|
errorrequired | object | Machine-readable code and a human-readable message. |
request_idrequired | string | Include this identifier when reporting a failed request. |
company_signals | CompanySignals | Optional company clues for enabled keys. A clue is not a confirmed employer. Check its flags; your main lookup result stays separate. |
Company16 fields
| Field | Type | Meaning |
|---|---|---|
namerequired | string | null | Company field; null when unavailable. |
websiterequired | string | null | Company field; null when unavailable. |
brand_namerequired | string | null | Marketing or alternate company name; not necessarily a registered brand. |
linkedin_urlrequired | string | null | Company field; null when unavailable. |
industryrequired | string | null | Company field; null when unavailable. |
industry_subcategoryrequired | string | null | Company field; null when unavailable. |
revenue_bandrequired | string | null | Company field; null when unavailable. |
naics_coderequired | string | null | Company field; null when unavailable. |
sic_coderequired | string | null | Company field; null when unavailable. |
cityrequired | string | null | Company field; null when unavailable. |
regionrequired | string | null | Company field; null when unavailable. |
postal_coderequired | string | null | Company field; null when unavailable. |
country_coderequired | string | null | Company field; null when unavailable. |
country_namerequired | string | null | Company field; null when unavailable. |
employeesrequired | string | integer | null | Reported employee count or range. Preserve strings; ranges are not exact headcounts and large counts may be decimal strings. |
annual_revenuerequired | string | integer | null | Annual sales value; currency and reporting period are unspecified. May be a decimal string to preserve precision. |
Lookup14 fields
| Field | Type | Meaning |
|---|---|---|
iprequired | string | The IP spelling you submitted. |
matched_iprequired | string | Exact spelling of the IP address that matched |
statusrequired | "complete" | complete is a finished lookup; pending and retrying are unfinished. |
match_typerequired | "company" | "isp" | "unclassified" | company: company information found; isp: internet service provider; unclassified: insufficient evidence to classify. Unclassified is not proof that the IP is not a business. |
company_foundrequired | boolean | True only when match_type is company. False for complete ISP/unclassified results. Pending responses instead use null. |
enriched_atrequired | string | null | UTC timestamp of the saved enrichment, not the current API request time. |
companyrequired | Company | null | All available company fields, including ISP/unclassified records; null only when every public company field is unavailable. Presence does not override network.is_isp or establish a non-ISP business match. |
networkrequired | object | Information about the IP connection. Fields can be null. |
request_idrequired | string | Include this identifier when reporting a failed request. |
stalerequired | boolean | Whether this saved result is due for refresh. Expiry does not remove available fields. |
fresh_untilrequired | string | null | Expiry of this saved result. Use this timestamp rather than assuming a fixed lifetime. Most company results last 30 days; some last 7 days. Null if no usable timestamp. |
refresh_statusrequired | "not_needed" | "not_requested" | "pending" | "deferred" | not_needed: no additional work needed; not_requested: this GET started no work (another request may have done so); pending: unfinished enrichment has been accepted; deferred: POST could not confirm or admit work, so retry POST after Retry-After. A saved ISP/unclassified result may be fresh while additional company enrichment is pending. |
refresh_errorrequired | null | "pending_limit" | "enrichment_limit" | "enrichment_capacity" | "submission_unconfirmed" | "lookup_failed" | Reason for deferred refresh. Existing data is still returned with HTTP 200. Apply daily/pending limits or temporary-error retry guidance. Unknown acknowledgement: repeat the same POST; do not assume no job exists. |
company_signals | CompanySignals | Optional company clues for enabled keys. A clue is not a confirmed employer. Check its flags; your main lookup result stays separate. |
Pending13 fields
| Field | Type | Meaning |
|---|---|---|
iprequired | string | The IP spelling you submitted. |
lookup_iprequired | string | Canonical form used for the enrichment request. |
statusrequired | "pending" | "retrying" | complete is a finished lookup; pending and retrying are unfinished. |
company_foundrequired | null | true only for a company match; false for completed ISP/unclassified results; null while pending. |
companyrequired | null | All available company fields, even when ISP or unclassified. Null only when no fields are available. |
submitted_atrequired | string | UTC time of the original API reservation. |
attemptsrequired | integer | Number of lookup attempts; 0 while awaiting the first attempt. |
next_retry_atrequired | string | null | Next scheduled retry in UTC, or null. Not a completion estimate. |
last_errorrequired | null | "lookup_failed" | lookup_failed means an unsuccessful lookup attempt, not a negative company match. |
status_urlrequired | string | Relative same-origin URL for getLookup. Send the same Bearer authentication; do not follow arbitrary external URLs. |
poll_after_secondsrequired | integer | Suggested minimum delay before the next GET poll; also provided by Retry-After. |
request_idrequired | string | Include this identifier when reporting a failed request. |
company_signals | CompanySignals | Optional company clues for enabled keys. A clue is not a confirmed employer. Check its flags; your main lookup result stays separate. |
Usage12 fields
| Field | Type | Meaning |
|---|---|---|
key_idrequired | string | Public key identifier; not the secret key. |
namerequired | string | Name assigned to this API key. |
fromrequired | string | Inclusive start in UTC. |
torequired | string | Exclusive end in UTC. |
timezonerequired | "UTC" | Always UTC. |
limitsrequired | object | Request-rate limits and optional daily enrichment budget. null means no daily cap; 0 means saved IPs only. |
totalsrequired | object | Requests, cache hits and average server processing time in milliseconds. |
outcomesrequired | object | Counts by company, isp, unclassified, enqueued, pending, retrying, invalid_request, rate_limited or error. |
hourlyrequired | array | Per-hour, per-outcome counters in UTC. |
accountingrequired | string | What the counters include and exclude. |
enrichmentrequired | EnrichmentStatus | Current enrichment status for the partner that owns this key; no IP list or other partners are exposed. |
reveals | RevealUsage |
EnrichmentStatus6 fields
| Field | Type | Meaning |
|---|---|---|
pendingrequired | integer | Unfinished unique enrichments started by this partner, shared across its keys. Current snapshot, independent of usage date range. |
submission_unconfirmedrequired | integer | Pending requests whose acceptance is not confirmed. Repeat the original POST to confirm. |
retryingrequired | integer | Pending IPs with at least one observed unsuccessful attempt. Updates periodically. |
oldest_pending_atrequired | string | null | Submission time of the oldest unfinished request, or null. |
oldest_checked_atrequired | string | null | Oldest status-check time among pending requests; null if none or any are not checked yet. Status updates can lag. |
completed_observed_last_minuterequired | integer | Requests observed to finish during the last minute; not a guaranteed completion rate. |
CompanySignals4 fields
| Field | Type | Meaning |
|---|---|---|
statusrequired | "available" | "unavailable" | unavailable means the clues could not be checked. An empty available list means no eligible recent clues were found. |
window_daysrequired | 30 | |
truncatedrequired | boolean | More evidence may exist than the bounded response includes. |
candidatesrequired | array |
CompanyCandidate11 fields
| Field | Type | Meaning |
|---|---|---|
domainrequired | string | Observed email domain, with common personal and reserved test domains excluded. Unlisted personal/disposable domains can still appear. |
companyrequired | Company | null | Profile matched by exact website hostname, ignoring www. Null if unmatched or multiple profiles share the domain. Subdomains are not guessed. |
verifiedrequired | false | |
evidencerequired | "submitted" | "field_only" | submitted records a browser submit event, not confirmed form acceptance. field_only means an email field was observed. |
first_seen_atrequired | string | First qualifying observation within the rolling 30-day window. |
last_seen_atrequired | string | |
observationsrequired | integer | Distinct captured events. Retries/replay are deduplicated; blur and submit can be separate events. |
submitted_observationsrequired | integer | |
observed_visitsrequired | integer | Distinct known page-run identifiers; 0 means none were recorded. Not a person or session count. |
sitesrequired | integer | Number of distinct website/installation combinations; their identities are private. |
flagsrequired | array | Reasons to treat a candidate cautiously. An empty list is not verification. Bot/connection flags describe the current IP classification, not necessarily its classification at observation time. |
CustomParameters
{
"type": "object",
"maxProperties": 32,
"propertyNames": {
"pattern": "^[A-Za-z][A-Za-z0-9_.-]{0,63}$",
"not": {
"enum": [
"constructor",
"prototype"
]
}
},
"additionalProperties": {
"anyOf": [
{
"type": "string",
"maxLength": 512
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
]
},
"description": "Installer-supplied, untrusted labels. Flat JSON object, at most 2048 UTF-8 bytes after JSON serialization. First accepted visit freezes custom for that session. Missing/legacy custom is {}. Never use these values for authorization or billing.",
"example": {
"account_id": "acme",
"campaign": "autumn",
"plan": "pro"
}
}TrackerCreate3 fields
| Field | Type | Meaning |
|---|---|---|
namerequired | string | Name assigned to this API key. |
originsrequired | array | |
customer_reference | string | null |
Tracker8 fields
| Field | Type | Meaning |
|---|---|---|
idrequired | string | |
namerequired | string | Name assigned to this API key. |
originsrequired | array | |
customer_referencerequired | string | null | |
created_atrequired | string | |
disabled_atrequired | string | null | |
snippetrequired | string | |
request_id | string | Include this identifier when reporting a failed request. |
TrackerDeleted4 fields
| Field | Type | Meaning |
|---|---|---|
idrequired | string | |
deletedrequired | true | |
deleted_atrequired | string | |
request_idrequired | string | Include this identifier when reporting a failed request. |
TrackerList2 fields
| Field | Type | Meaning |
|---|---|---|
trackersrequired | array | |
request_idrequired | string | Include this identifier when reporting a failed request. |
TrackerUsage11 fields
| Field | Type | Meaning |
|---|---|---|
tracker_idrequired | string | |
fromrequired | string | Inclusive start in UTC. |
torequired | string | Exclusive end in UTC. |
timezonerequired | "UTC" | Always UTC. |
totalsrequired | object | Requests, cache hits and average server processing time in milliseconds. |
hourlyrequired | array | Per-hour, per-outcome counters in UTC. |
pending_revealsrequired | integer | |
metrics_started_atrequired | string | |
partial_historyrequired | boolean | True if this tracker existed before full counters started and the range includes that earlier time. Earlier sessions and reveals include retained records only; zero may represent missing history. |
accountingrequired | string | What the counters include and exclude. |
request_id | string | Include this identifier when reporting a failed request. |
SessionPreview9 fields
| Field | Type | Meaning |
|---|---|---|
session_idrequired | string | |
tracker_idrequired | string | |
customer_referencerequired | string | null | |
custom | CustomParameters | |
visitor_countryrequired | string | null | Estimated visitor IP country, not company headquarters. null means unknown. VPNs can affect location. |
first_seen_atrequired | string | |
last_seen_atrequired | string | |
expires_atrequired | string | |
request_id | string | Include this identifier when reporting a failed request. |
SessionFeed4 fields
| Field | Type | Meaning |
|---|---|---|
sessionsrequired | array | |
next_cursorrequired | string | |
has_morerequired | boolean | |
request_idrequired | string | Include this identifier when reporting a failed request. |
RevealResult10 fields
| Field | Type | Meaning |
|---|---|---|
statusrequired | "complete" | complete is a finished lookup; pending and retrying are unfinished. |
match_typerequired | "company" | "isp" | "unclassified" | company: company information found; isp: internet service provider; unclassified: insufficient evidence to classify. Unclassified is not proof that the IP is not a business. |
company_foundrequired | boolean | True only when match_type is company. False for complete ISP/unclassified results. Pending responses instead use null. |
enriched_atrequired | string | null | UTC timestamp of the saved enrichment, not the current API request time. |
companyrequired | Company | null | All available company fields, including ISP/unclassified records; null only when every public company field is unavailable. Presence does not override network.is_isp or establish a non-ISP business match. |
networkrequired | object | Information about the IP connection. Fields can be null. |
stalerequired | boolean | Whether this saved result is due for refresh. Expiry does not remove available fields. |
fresh_untilrequired | string | null | Expiry of this saved result. Use this timestamp rather than assuming a fixed lifetime. Most company results last 30 days; some last 7 days. Null if no usable timestamp. |
refresh_statusrequired | "not_needed" | "not_requested" | "pending" | "deferred" | not_needed: no additional work needed; not_requested: this GET started no work (another request may have done so); pending: unfinished enrichment has been accepted; deferred: POST could not confirm or admit work, so retry POST after Retry-After. A saved ISP/unclassified result may be fresh while additional company enrichment is pending. |
refresh_errorrequired | null | "pending_limit" | "enrichment_limit" | "enrichment_capacity" | "submission_unconfirmed" | "lookup_failed" | Reason for deferred refresh. Existing data is still returned with HTTP 200. Apply daily/pending limits or temporary-error retry guidance. Unknown acknowledgement: repeat the same POST; do not assume no job exists. |
Reveal13 fields
| Field | Type | Meaning |
|---|---|---|
reveal_idrequired | string | |
session_idrequired | string | |
tracker_idrequired | string | |
custom | CustomParameters | |
statusrequired | "pending" | "complete" | complete is a finished lookup; pending and retrying are unfinished. |
billablerequired | boolean | True when this reveal has one recorded billable unit. Re-reading this receipt does not charge again. |
billable_unitsrequired | 0 | 1 | |
created_atrequired | string | |
completed_atrequired | string | null | |
expires_atrequired | string | |
resultrequired | RevealResult | null | |
status_urlrequired | string | Relative GET URL for checking this IP again. |
request_idrequired | string | Include this identifier when reporting a failed request. |
RevealUsage4 fields
| Field | Type | Meaning |
|---|---|---|
billable_revealsrequired | integer | |
completed_revealsrequired | integer | |
hourlyrequired | array | Per-hour, per-outcome counters in UTC. |
accountingrequired | string | What the counters include and exclude. |
WebhookCreate4 fields
| Field | Type | Meaning |
|---|---|---|
namerequired | string | Name assigned to this API key. |
urlrequired | string | Public HTTPS on port443; no credentials, fragment, private addresses or redirects. Immutable; create a new endpoint to change it. |
eventsrequired | array | |
tracker_id | string | null | Omit or null for all trackers owned by this partner. |
WebhookUpdate3 fields
| Field | Type | Meaning |
|---|---|---|
name | string | Name assigned to this API key. |
events | array | |
enabled | boolean |
Webhook12 fields
| Field | Type | Meaning |
|---|---|---|
idrequired | string | |
namerequired | string | Name assigned to this API key. |
urlrequired | string | |
eventsrequired | array | |
tracker_idrequired | string | null | |
enabledrequired | boolean | |
created_atrequired | string | |
updated_atrequired | string | |
deleted_atrequired | string | null | |
secret_rotation_untilrequired | string | null | |
deliveriesrequired | object | |
request_id | string | Include this identifier when reporting a failed request. |
WebhookSecret13 fields
| Field | Type | Meaning |
|---|---|---|
idrequired | string | |
namerequired | string | Name assigned to this API key. |
urlrequired | string | |
eventsrequired | array | |
tracker_idrequired | string | null | |
enabledrequired | boolean | |
created_atrequired | string | |
updated_atrequired | string | |
deleted_atrequired | string | null | |
secret_rotation_untilrequired | string | null | |
deliveriesrequired | object | |
request_id | string | Include this identifier when reporting a failed request. |
signing_secretrequired | string | Shown once on creation/rotation. Verify HMAC SHA-256 signatures server-side. Never send this secret to a browser installation snippet. |
WebhookList4 fields
| Field | Type | Meaning |
|---|---|---|
webhooksrequired | array | |
limitsrequired | object | Request-rate limits and optional daily enrichment budget. null means no daily cap; 0 means saved IPs only. |
workerrequired | object | |
request_id | string | Include this identifier when reporting a failed request. |
WebhookDeleted4 fields
| Field | Type | Meaning |
|---|---|---|
idrequired | string | |
deletedrequired | true | |
deleted_atrequired | string | |
request_id | string | Include this identifier when reporting a failed request. |
WebhookTest4 fields
| Field | Type | Meaning |
|---|---|---|
delivery_idrequired | string | |
event_idrequired | string | |
statusrequired | "pending" | complete is a finished lookup; pending and retrying are unfinished. |
request_id | string | Include this identifier when reporting a failed request. |
WebhookRevealReceipt12 fields
| Field | Type | Meaning |
|---|---|---|
reveal_idrequired | string | |
session_idrequired | string | |
tracker_idrequired | string | |
custom | CustomParameters | |
statusrequired | "pending" | "complete" | complete is a finished lookup; pending and retrying are unfinished. |
billablerequired | boolean | True when this reveal has one recorded billable unit. Re-reading this receipt does not charge again. |
billable_unitsrequired | 0 | 1 | |
created_atrequired | string | |
completed_atrequired | string | null | |
expires_atrequired | string | |
resultrequired | RevealResult | null | |
status_urlrequired | string | Relative GET URL for checking this IP again. |
WebhookEvent
{
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"type": {
"const": "session.created"
},
"schema_version": {
"const": 1
},
"created_at": {
"type": "string",
"format": "date-time"
},
"data": {
"$ref": "#/components/schemas/SessionPreview"
}
},
"required": [
"id",
"type",
"schema_version",
"created_at",
"data"
]
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"type": {
"const": "reveal.completed"
},
"schema_version": {
"const": 1
},
"created_at": {
"type": "string",
"format": "date-time"
},
"data": {
"$ref": "#/components/schemas/WebhookRevealReceipt"
}
},
"required": [
"id",
"type",
"schema_version",
"created_at",
"data"
]
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"type": {
"const": "webhook.test"
},
"schema_version": {
"const": 1
},
"created_at": {
"type": "string",
"format": "date-time"
},
"data": {
"type": "object",
"additionalProperties": false,
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
]
}
},
"required": [
"id",
"type",
"schema_version",
"created_at",
"data"
]
}
],
"examples": [
{
"id": "evt_session_00000000-0000-4000-8000-000000000001",
"type": "session.created",
"schema_version": 1,
"created_at": "2026-09-25T12:00:00.000Z",
"data": {
"session_id": "00000000-0000-4000-8000-000000000001",
"tracker_id": "00000000-0000-4000-8000-000000000002",
"customer_reference": "acme",
"custom": {
"account_id": "acme",
"campaign": "autumn",
"plan": "pro"
},
"visitor_country": "GB",
"first_seen_at": "2026-09-25T12:00:00.000Z",
"last_seen_at": "2026-09-25T12:00:00.000Z",
"expires_at": "2026-10-25T12:00:00.000Z"
}
},
{
"id": "evt_reveal_00000000-0000-4000-8000-000000000003",
"type": "reveal.completed",
"schema_version": 1,
"created_at": "2026-09-25T12:00:00.000Z",
"data": {
"reveal_id": "00000000-0000-4000-8000-000000000003",
"session_id": "00000000-0000-4000-8000-000000000001",
"tracker_id": "00000000-0000-4000-8000-000000000002",
"custom": {
"account_id": "acme",
"campaign": "autumn",
"plan": "pro"
},
"status": "complete",
"billable": true,
"billable_units": 1,
"created_at": "2026-09-25T12:00:00.000Z",
"completed_at": "2026-09-25T12:00:00.000Z",
"expires_at": "2026-10-25T12:00:00.000Z",
"result": {
"status": "complete",
"match_type": "company",
"company_found": true,
"enriched_at": "2026-09-18T12:00:00.000Z",
"stale": false,
"fresh_until": "2026-10-18T12:00:00.000Z",
"refresh_status": "not_needed",
"refresh_error": null,
"network": {
"connection_type": "Business",
"audience_type": "Business",
"audience_group": null,
"detail_level": null,
"is_isp": false
},
"company": {
"name": "Example Company",
"website": "example.com",
"brand_name": null,
"linkedin_url": null,
"industry": "Software",
"industry_subcategory": null,
"employees": "120",
"annual_revenue": null,
"revenue_band": null,
"naics_code": "541511",
"sic_code": null,
"city": "London",
"region": null,
"postal_code": null,
"country_code": "GB",
"country_name": "United Kingdom"
}
},
"status_url": "/v1/reveals/00000000-0000-4000-8000-000000000003"
}
}
]
}WebhookDelivery11 fields
| Field | Type | Meaning |
|---|---|---|
idrequired | string | |
event_idrequired | string | |
typerequired | "session.created" | "reveal.completed" | "webhook.test" | |
staterequired | "pending" | "delivered" | "failed" | "cancelled" | "expired" | |
attemptsrequired | integer | Number of lookup attempts; 0 while awaiting the first attempt. |
created_atrequired | string | |
last_attempt_atrequired | string | null | |
delivered_atrequired | string | null | |
next_attempt_atrequired | string | null | |
http_statusrequired | integer | null | |
errorrequired | string | null | Machine-readable code and a human-readable message. |
WebhookDeliveryDetail13 fields
| Field | Type | Meaning |
|---|---|---|
idrequired | string | |
event_idrequired | string | |
typerequired | "session.created" | "reveal.completed" | "webhook.test" | |
staterequired | "pending" | "delivered" | "failed" | "cancelled" | "expired" | |
attemptsrequired | integer | Number of lookup attempts; 0 while awaiting the first attempt. |
created_atrequired | string | |
last_attempt_atrequired | string | null | |
delivered_atrequired | string | null | |
next_attempt_atrequired | string | null | |
http_statusrequired | integer | null | |
errorrequired | string | null | Machine-readable code and a human-readable message. |
eventrequired | WebhookEvent | null | |
request_id | string | Include this identifier when reporting a failed request. |
WebhookDeliveryList4 fields
| Field | Type | Meaning |
|---|---|---|
deliveriesrequired | array | |
has_morerequired | boolean | |
next_cursorrequired | string | |
request_id | string | Include this identifier when reporting a failed request. |
Network5 fields
| Field | Type | Meaning |
|---|---|---|
connection_typerequired | string | null | Type of internet connection; nullable. |
audience_typerequired | string | null | Audience category; nullable. |
audience_grouprequired | string | null | Audience segment; nullable. |
detail_levelrequired | string | null | Available detail level; nullable. |
is_isprequired | boolean | null | True: internet service provider. False: non-ISP. Null: unspecified. False alone does not establish a company match; use company_found and match_type. |
The downloadable OpenAPI file includes schemas, examples, authentication, response headers and the complete application-error catalog under x-error-codes and x-tracking-error-codes.
Usage limits & retries
- Use
GET /v1/usageto read the limits assigned to your key. Request-rate limits apply to authenticated API calls; lookup responses and successful tracker/session/reveal calls count as requests. Billable reveal units are listed separately underreveals. - Keys belonging to the same partner share a limit for unfinished enrichments. Check
enrichmentandlimits.pending_enrichmentsin your usage response. A429 pending_limitmeans wait for existing work to finish; saved lookups still work. - The daily budget is optional:
limits.new_enrichments_per_day: nullmeans no daily cap;0means saved IPs only. When set, each new reservation uses that budget, even if submission needs a retry. It resets at 00:00 UTC. Reads use no new reservation. A refresh uses a reservation just like a new lookup. - For 202 responses, wait at least
Retry-Afterseconds (currently 15) between manual or application polls. No enrichment completion deadline is promised. - For temporary 429/503 failures, honor
Retry-Afterand use exponential backoff with jitter.enrichment_limitrequires the next UTC day or a limit increase. - Use
fresh_untilto see when saved details expire. POST can return those details while looking for newer or more complete information.refresh_status: pendingmeans accepted;deferredmeans checkrefresh_errorand retry POST later. GET only reads. Poll the same IP afterRetry-Afteruntilstale: falseandrefresh_status: not_needed. Completed results can be cached for up to 60 seconds. New lookups may take longer; no completion time is guaranteed. - The API supports public IPv4, native IPv6 and IPv4-mapped IPv6. Equivalent address spellings may match the same result.