Scanlead

PUBLIC API V1

Available on Pro and Pro+ plans

Connect Scanlead to your tools.

Read and create leads from Make, Zapier, your CRM, ERP or a script.

Get started in 3 steps

01

Create a key in Settings → API.

02

Send your first curl request with Bearer.

03

Add a webhook to receive new leads.

Connect CRMlead

  1. 01In CRMlead → Settings → Integrations → Connect Scanlead → Allow.
  2. 02OAuth 2.0 with PKCE shares no secret (Pro and Pro+ plans).

On Free, export a CSV and then import it into CRMlead.

For future apps: use GET /oauth/authorize and POST /oauth/token with OAuth 2.0 authorization code + PKCE S256.

OAuth for applications

Register a public client with exact redirect URLs and allowed scopes. No client secret. Generate a random code_verifier (43–128 characters), then code_challenge = BASE64URL(SHA256(code_verifier)), without padding. The resulting code expires after 2 minutes and is single-use.

GET /oauth/authorize?response_type=code&client_id=crmlead&redirect_uri=<registered_uri>&scope=read&state=<random_state>&code_challenge=<S256_challenge>&code_challenge_method=S256

Exchange the code using an application/x-www-form-urlencoded POST. The response contains access_token (a v1 API key), token_type=Bearer, scope=read and workspace { id, name }. Keep the token secure; Settings → API can revoke it. /oauth/token does not support CORS.

POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id=crmlead&code=<code>&redirect_uri=<registered_uri>&code_verifier=<original_verifier>

For Zapier, Make or your scripts, create a key to paste manually in Scanlead → Settings → API instead.

Routes

Event lists return { data: [...] }. To create a lead, only email is required; all other fields are optional. PATCH accepts any subset, including event_id.

The status field is accepted on create and update. Allowed values: hot, warm, or cold.

GET/me
curl https://scanlead.io/api/v1/me \
  -H "Authorization: Bearer slk_live_YOUR_KEY"
GET/events
curl https://scanlead.io/api/v1/events \
  -H "Authorization: Bearer slk_live_YOUR_KEY"
GET/events/{id}
curl https://scanlead.io/api/v1/events/{id} \
  -H "Authorization: Bearer slk_live_YOUR_KEY"
GET/leads?limit=50
curl https://scanlead.io/api/v1/leads?limit=50 \
  -H "Authorization: Bearer slk_live_YOUR_KEY"
GET/leads/{id}
curl https://scanlead.io/api/v1/leads/{id} \
  -H "Authorization: Bearer slk_live_YOUR_KEY"
POST/leads
curl https://scanlead.io/api/v1/leads \
  -H "Authorization: Bearer slk_live_YOUR_KEY" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"first_name":"Ada","last_name":"Lovelace","email":"ada@example.com","company":"Analytical Engines","tags":["vip"],"status":"hot"}'
PATCH/leads/{id}
curl https://scanlead.io/api/v1/leads/{id} \
  -H "Authorization: Bearer slk_live_YOUR_KEY" \
  -X PATCH \
  -H "Content-Type: application/json" \
  -d '{"notes":"Follow up next week","status":"warm"}'

Authentication and signatures

Use Authorization: Bearer slk_live_…. Keys are scoped read or read_write. Webhooks include Scanlead-Signature: t=timestamp,v1=hex, computed as HMAC-SHA256(secret, timestamp.body).

Verify a webhook signature: Node.js

const crypto = require('node:crypto');
const expected = crypto.createHmac('sha256', secret).update(`${t}.${body}`).digest('hex');
if (expected !== signature) throw new Error('invalid signature');

Python

import hmac, hashlib
expected = hmac.new(secret.encode(), f'{t}.{body}'.encode(), hashlib.sha256).hexdigest()
assert hmac.compare_digest(expected, signature)

Limits

60 requests per minute per key. Lead lists accept 1–100 items and use an opaque cursor.

Error codes

  • 401 invalid_api_key: missing, unknown or revoked key
  • 403 insufficient_scope: a read key was used for a write
  • 404 not_found: the resource belongs to another workspace
  • 429 rate_limited: retry after the Retry-After header
  • 400 unknown_fields: unsupported field names are returned in error.fields. Example: { error: { code: "unknown_fields", fields: ["full_name"] } }.
  • 402 plan_required: Pro or Pro+ subscription required
View the OpenAPI 3.1 schema →