API reference

Lead Ingest API

Push leads into your AnchorLeads pipeline from EverQuote, Datalot, custom forms, Zapier, or your own funnels. REST, JSON, per-agent Bearer-token auth.

TCPA responsibility

Every lead ingested through this API must have documented prior express written consent from the consumer to receive autodialed marketing calls and texts. Best practice — and your strongest defense in a TCPA complaint — is a disclosure that names the receiving advisor (or their firm) as the recipient, retained verbatim with timestamp and IP. The endpoint rejects any request where consent !== true. Statutory damages for a TCPA violation are $500–$1,500 per text or call. AnchorLeads does not indemnify agents for non-compliant imports.

Endpoint

POST /api/ingest/leads Host: anchorleads.io Authorization: Bearer al_live_YOUR_KEY_HERE Content-Type: application/json

Generate a key in Agent settings → API keys. The plaintext key is shown exactly once at creation — store it in your integration's secrets manager. We only keep a SHA-256 hash.

Request body

FieldTypeRequiredDescription
first_namestringrequiredProspect first name. 1–80 chars.
last_namestringrequiredProspect last name. 1–80 chars.
emailstringrequiredValid email. Lowercased server-side.
phonestringrequiredUS phone. 10 digits or E.164. Normalized server-side.
consentboolean (must be true)requiredConsent to be contacted. Rejected if not exactly true.
consent_timestampISO 8601 datetimeoptionalWhen the prospect gave consent. Defaults to now.
consent_disclosurestring ≤ 4000optionalVerbatim disclosure text the prospect agreed to. Retained for audit.
consent_urlURL string ≤ 500optionalThe page where consent was captured. Retained for audit.
consent_ipstring ≤ 64optionalThe prospect's IP at consent time. Retained for audit.
sourcestring ≤ 80optionalFree-form source label. Stored on the lead as lead_source (e.g., "everquote", "custom_form").
funnel_type"coverage_gap" | "iul_tax_savings"optionalProduct interest. Defaults to "coverage_gap".
lead_type"iul" | "term"optionalProduct classification, if known.
metadataJSON objectoptionalArbitrary tags stored on the lead's created event.

Examples

curl

curl -X POST https://anchorleads.io/api/ingest/leads \
  -H "Authorization: Bearer al_live_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Michael",
    "last_name": "Reyes",
    "email": "michael@example.com",
    "phone": "+15551234501",
    "consent": true,
    "consent_timestamp": "2026-07-07T15:04:00Z",
    "consent_disclosure": "By checking this box I agree to receive marketing calls and text messages from Michael Advisor at the number I provided...",
    "consent_url": "https://youracquisitionsite.com/quote-form",
    "consent_ip": "184.28.14.9",
    "source": "everquote",
    "funnel_type": "iul_tax_savings",
    "lead_type": "iul",
    "metadata": { "campaign": "fb-tax-drag-2026-07", "cost_per_lead": 27.50 }
  }'

Node.js

const res = await fetch('https://anchorleads.io/api/ingest/leads', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ANCHORLEADS_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    first_name: lead.firstName,
    last_name:  lead.lastName,
    email:      lead.email,
    phone:      lead.phone,
    consent:    true,
    consent_timestamp:  lead.consentAt,
    consent_disclosure: lead.disclosureText,
    consent_url:        lead.consentPageUrl,
    consent_ip:         lead.consentIp,
    source:             'custom_form',
  }),
});
const json = await res.json();
if (!res.ok || !json.success) {
  console.error('Ingest failed:', json);
  throw new Error(json.message ?? 'Ingest failed');
}
console.log('Lead created:', json.data.lead_id, 'deduped:', json.data.deduped);

Python

import os, requests

payload = {
    "first_name": lead["first_name"],
    "last_name":  lead["last_name"],
    "email":      lead["email"],
    "phone":      lead["phone"],
    "consent":    True,
    "consent_timestamp":  lead["consent_at"],
    "consent_disclosure": lead["disclosure"],
    "consent_url":        lead["consent_page_url"],
    "source":             "custom_form",
}

resp = requests.post(
    "https://anchorleads.io/api/ingest/leads",
    headers={
        "Authorization": f"Bearer {os.environ['ANCHORLEADS_KEY']}",
        "Content-Type":  "application/json",
    },
    json=payload,
    timeout=10,
)
resp.raise_for_status()
data = resp.json()["data"]
print("Lead created:", data["lead_id"], "deduped:", data["deduped"])

Responses

201 Created

{ "success": true, "data": { "lead_id": "uuid", "deduped": false, "do_not_contact": false } }

New lead accepted and saved.

200 OK (deduped)

{ "success": true, "data": { "lead_id": "uuid", "deduped": true } }

Same phone or email already exists in this agent's book within the last 30 days. Existing lead is returned.

400 Bad Request

{ "success": false, "error": "validation_error", "field": "consent", "message": "consent must be exactly true..." }

Schema validation failed or consent was missing / not exactly true.

401 Unauthorized

{ "success": false, "error": "missing_token" | "invalid_token" | "unknown_key" | "revoked" }

Authorization header missing, malformed, or does not resolve to an active key.

403 Forbidden

{ "success": false, "error": "tcpa_ack_required" | "expired" | "scope_denied" }

Key was created but the TCPA clause was never accepted, is expired, or lacks the leads:write scope.

429 Too Many Requests

{ "success": false, "error": "rate_limited" }
Header: Retry-After: <seconds>

Daily rate limit reached. Retry after the given delay.

Behavior

  • Dedupe

    If the same phone or email already exists in this agent's book within the last 30 days, we return the existing lead ID with deduped: true. No duplicate row is created.

  • DNC suppression

    Every ingested phone is checked against prior STOP records for the agent. Matches are still saved but with do_not_contact = true, and all outbound automations skip them.

  • Consent audit trail

    consent_disclosure, consent_url, consent_ip, and consent_timestamp are stored verbatim on the lead. Retain the original consent evidence on your side too — this is your defense record if a TCPA claim is filed.

  • Rate limits

    Each key has a per-day cap (default 500). Exceeding it returns 429 with a Retry-After header pointing to midnight UTC. Adjust the cap when creating the key.

  • No CORS

    This is a server-to-server API. Browser requests are not allowed. Do not put your API key in client-side code.

Ready to wire up an integration?

Generate a key in Agent Settings, drop it in your source's webhook config, and you're live.

Sign in to generate a keySee pricing