1Lookup · AsyncAPI Specification

1Lookup Webhooks

Version

View Spec View on GitHub phone validationemail validationIP intelligencefraud & riskdata enrichmentB2B contact & company dataSEO / web analyticsaudio transcriptionMCP / agent-nativeREST APIAsyncAPIWebhooksEvents

AsyncAPI Specification

1lookup-webhooks.yml Raw ↑
generated: '2026-08-14'
method: searched
source: https://app.1lookup.io/api
docs: https://app.1lookup.io/api
spec_type: none
description: >-
  1Lookup ships an outbound webhook surface — new since the 2026-08-09 pass, which correctly recorded
  "no event surface" against the reference as it stood then. The rewritten reference now documents a
  dedicated "Webhooks" core-concept section plus a `webhook_url` parameter on two resources: bulk jobs
  (one call when the job finishes) and job-change monitors (one call per detected change). Deliveries
  are HMAC-SHA256 signed with a per-monitor secret. There is NO AsyncAPI document, no event catalog,
  no SSE/WebSocket stream and no subscription-management API — the whole surface is the two
  `webhook_url` fields below, so this file is the webhook catalog, not a spec harvest.
publishes_asyncapi: false
asyncapi_probed:
  - {url: 'https://app.1lookup.io/asyncapi.yaml', status: 200, content_type: text/html, parsed: false, note: 'Next.js catch-all HTML shell — soft-404, not a spec'}
  - {url: 'https://app.1lookup.io/asyncapi.json', status: 200, content_type: text/html, parsed: false, note: 'Next.js catch-all HTML shell — soft-404, not a spec'}
  - {url: 'https://www.1lookup.io/asyncapi.yaml', status: 404}
transport:
  style: outbound HTTP POST callback
  content_type: application/json
  tls_required: true
  note: >-
    The registered URL must be HTTPS and publicly resolvable; private and loopback addresses are
    rejected at registration.
registration:
  model: per-resource parameter (no webhook-management API)
  endpoints:
    - operation: 'POST /api/v1/bulk/jobs'
      parameter: webhook_url
      required: false
      description: HTTPS endpoint called once when the bulk job finishes.
    - operation: 'POST /api/v1/job-change-monitors'
      parameter: webhook_url
      required: false
      description: HTTPS endpoint for job-change events on the monitored contacts.
  secret:
    field: webhook_secret
    prefix: whsec_
    returned: >-
      Once only, in the response that created the monitor. Never shown again — store it at create time.
    note: >-
      The reference documents the secret as returned on monitor create. Bulk-job callbacks are stated to
      be "signed with the same scheme as monitor webhooks"; the docs do not say which secret keys a
      bulk-job delivery, and that is recorded here as a published gap rather than guessed.
signing:
  algorithm: HMAC-SHA256
  header: X-1Lookup-Signature
  format: 'sha256=<hex digest>'
  signed_payload: the raw request body
  comparison: constant-time (docs supply a timingSafeEqual example)
  example_header: 'X-1Lookup-Signature: sha256=9f86d081884c7d65…'
delivery:
  attempts: 1
  retries: none
  timeout_seconds: 5
  redirects_followed: false
  expected_response: 2xx, returned quickly; do the work asynchronously
  ordering: not documented
  replay_protection: no timestamp/nonce documented beyond the body HMAC
  guidance: >-
    The provider states plainly that "a webhook is a hint, not the record": because delivery is
    single-attempt, a consumer should treat the callback as a prompt to GET the job or the monitor's
    events rather than as the system of record.
events:
  - name: bulk.job.finished
    published_name: null
    source_operation: 'POST /api/v1/bulk/jobs'
    trigger: The bulk job reaches a terminal status.
    delivery: One POST to the job's registered webhook_url.
    follow_up: 'GET /api/v1/bulk/jobs/{job_id} — read status, counters and a fresh signed results_url.'
    note: >-
      The reference does not publish an event name or the callback body schema; only the trigger and the
      signing scheme are documented. Recorded as documented, not modelled.
  - name: monitor.job_change.detected
    published_name: null
    source_operation: 'POST /api/v1/job-change-monitors'
    trigger: A weekly recheck finds a monitored contact has changed role or company.
    delivery: One signed POST per detected change to the monitor's webhook_url.
    follow_up: 'GET /api/v1/job-change-monitors/{id}/events?page=&limit= — the authoritative event list.'
    payload_note: >-
      The docs say the event "names the old and new roles"; the exact field names are not published.
    email_alternative: 'alert_email (boolean, default true) sends the same change alert by email.'
polling_alternative:
  bulk_jobs: 'GET /api/v1/bulk/jobs/{job_id} and /results — free, and excluded from the lookup rate budget.'
  monitors: 'GET /api/v1/job-change-monitors/{id}/events with page and limit.'
verification_example:
  language: javascript
  source: https://app.1lookup.io/api
  code: |
    import crypto from "node:crypto";

    // Verify against the RAW body — parse only after the check passes.
    export function isFrom1Lookup(rawBody, header, secret) {
      const received = String(header ?? "").replace(/^sha256=/, "");
      const expected = crypto
        .createHmac("sha256", secret)
        .update(rawBody)
        .digest("hex");
      const a = Buffer.from(received, "hex");
      const b = Buffer.from(expected, "hex");
      return a.length === b.length && crypto.timingSafeEqual(a, b);
    }
gaps:
  - No AsyncAPI document, so the event surface is not machine-readable.
  - No published event names, versions, or callback body schemas.
  - No webhook-management API — endpoints are set per job/monitor and cannot be listed or rotated.
  - Single-attempt delivery with no retry, no dead-letter and no delivery log.
  - No timestamp in the signature scheme, so replay windows must be enforced by the consumer.
x-evidence:
  - url: https://app.1lookup.io/api
    http_status: 200
    fetched: '2026-08-14'
    note: >-
      "Webhooks" core-concept section, plus webhook_url/webhook_secret parameters on the bulk-job and
      job-change-monitor endpoints.