Skip to main content
Search...C
Insertion API

Create Lead

Inserts (or idempotently upserts) a lead into your account via the Public Insertion API. The pipeline is identical to the internal /api/leads/ingest path — including idempotency on (account_id, campaign_id, external_lead_id), score-gated delivery, and workflow scheduling.

Endpoint

POST/api/v1/insertion/leads

Authentication

Two paths are accepted. HMAC-SHA256 signing is preferred. POST requires the leads:write scope on the API key. See the dedicated Authentication guide for the full signing recipe and Node/Python examples.

HMAC headers (preferred)
X-AdBuy-Public-Key:  pk_live_<random>_<last4>
X-AdBuy-Timestamp:   <unix-seconds>             (±5min replay window)
X-AdBuy-Signature:   <hex>                       HMAC_SHA256(secret, ts + "." + rawBody)
Bearer token (fallback)
Authorization: Bearer sk_live_<...>

Request Body

NameTypeDescription
campaign_idrequiredintegerAdBuy campaign id to attach the lead to.
external_lead_idrequireduuidCaller-supplied UUID. Idempotency key together with campaign_id.
phonestringE.164 or local phone. 10–50 chars.
emailstringUp to 320 chars.
first_namestringUp to 100 chars.
last_namestringUp to 100 chars.
sourcestringLead source label.
source_form_urlstringURL the lead originated from.
ip_addressstringClient IP captured at submit time.
tcpa_consentbooleanWhether TCPA consent was obtained.
tcpa_consent_textstringExact consent string presented to the user.
tcpa_consent_timestampstringISO 8601 timestamp when consent was obtained.
custom_fieldsobjectArbitrary JSON object stored with the lead.
workflow_idsuuid[]Optional override list of workflow ids to schedule.

At least one of phone or email must be present. All other fields are optional. Unknown fields are rejected by the Zod schema with 400 invalid_payload.

Response

Response Schema
{
  "ok": true,
  "status": "inserted" | "patched" | "deduped",
  "lead": {
    "id": "uuid",
    "user_id": "uuid",
    "campaign_id": 123
  }
}

Status semantics:

  • inserted — first time this (campaign_id, external_lead_id) tuple was seen. Response code 201.
  • patched — same tuple, mutated fields applied to the existing lead. Response code 200.
  • deduped — exact replay; no changes made. Response code 200.

See Errors & Idempotency for the full error envelope and retry strategy.

Example

cURL (Bearer)
curl -X POST "https://api.adbuy.ai/api/v1/insertion/leads" \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": 123,
    "external_lead_id": "f6b1d3c0-1234-4abc-9def-0123456789ab",
    "phone": "+15551234567",
    "email": "lead@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "tcpa_consent": true
  }'
cURL (HMAC)
BODY='{"campaign_id":123,"external_lead_id":"f6b1d3c0-1234-4abc-9def-0123456789ab","phone":"+15551234567"}'
TS=$(date +%s)
SIG=$(printf "%s.%s" "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')

curl -X POST "https://api.adbuy.ai/api/v1/insertion/leads" \
  -H "X-AdBuy-Public-Key: pk_live_..." \
  -H "X-AdBuy-Timestamp: $TS" \
  -H "X-AdBuy-Signature: $SIG" \
  -H "Content-Type: application/json" \
  -d "$BODY"
Response (201 Created)
{
  "ok": true,
  "status": "inserted",
  "lead": {
    "id": "1d8e1c2a-9b3e-4a4f-9c1e-2b0a1d8e1c2a",
    "user_id": "0a1b2c3d-4e5f-6789-abcd-ef0123456789",
    "campaign_id": 123
  }
}