Lead Distro AILead Distro AI
DocsAPI ReferenceLead Ingest API

Lead Ingest API

Complete Lead Distro AI API reference: the Actions API for managing your account with an organization API key (with an OpenAPI file), plus the lead ingest endpoint with field validation, test leads, the buyer postback webhook, authentication, and rate limits.

Last updated:

Actions API (manage your account)

Everything you can do by chat through the MCP, you can also do over plain HTTPS from a script, a workflow tool, or your own app: create and update campaigns, destinations, sources and funnels, look up leads and their routing trail, post back outcomes, pull reports, and manage Partner Portal access. Same action names, same inputs, same permissions.

Authentication

Use an organization API key (created in Settings, MCP & API) as a bearer token. A key holds per-area permissions, read or write, and starts read only. See Authentication.

Authorization: Bearer ldk_live_...

Endpoints

Method and pathWhat it does
GET /api/v1/openapi.jsonThe full reference as an OpenAPI 3.1 file. Public. Import it into your API client or SDK generator.
GET /api/v1/whoamiWhich organization your key acts for, its permissions, and which actions it may run.
GET /api/v1/actionsEvery action with its description, input schema, required permission, and whether your key may call it.
POST /api/v1/actions/{action}Run one action. The JSON body is the action's input.
POST /api/v1/campaigns/{id}/pause and POST /api/v1/campaigns/{id}/resumePause or resume a whole campaign. Needs the campaigns:write permission. Returns 409 when it is already in that state. Resuming a calls campaign returns 402 until your calls balance (or auto-recharge) can cover live calls.
POST /api/v1/campaigns/{id}/buyers/{buyerId}/pause and POST /api/v1/campaigns/{id}/buyers/{buyerId}/resumePause or resume one destination on one campaign, without touching its other campaigns. Needs campaigns:write. Resume returns 409 while the destination has no delivery set up, and 403 when your plan's limit on active destinations is reached.
POST /api/v1/leads/returnReturn one lead (it shows as Returned), with the same credit, cap and wallet refund steps as returning it in the app. Needs leads:write. Body: lead_id, reason (wrong_number, no_response, duplicate, bad_data, not_qualified, other, or your own text such as "Bad Phone"), and optional description, buyer_id (which destination's copy, on a shared lead), credit_amount, and direction (buyer refunds the destination, the default; supplier only notifies the source; both). Returns 201 with return_id and credit_amount.

Example

curl -X POST https://www.leaddistro.ai/api/v1/actions/get_campaign \
  -H "Authorization: Bearer ldk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"campaign_id": "<campaign uuid>"}'
{
  "success": true,
  "data": { "id": "...", "name": "Auto Insurance CA", "status": "ACTIVE" }
}

Responses and errors

StatusMeaning
200The action ran. data holds its result.
400The action ran and reported a problem (for example, a record was not found), or the body was not a JSON object. error explains.
401Missing, invalid, or revoked key.
403The key does not hold the permission this action needs. required names it.
404No action by that name. Check GET /api/v1/actions.
422The body failed validation. details lists the fields.
429Rate limit. Read the Retry-After header. Limits per key: 120 requests per minute, 30 writes per minute.

Billing actions (charges, refunds, wallets) are never available through the API, and a key only ever acts inside the organization it was created in.


Lead Ingest API

Send leads into Lead Distro AI using a simple POST request. Leads are validated against your campaign's field mapping, checked against inbound filters and suppression lists, then distributed to buyers automatically.

Endpoint

POST https://app.leaddistro.ai/api/v1/ingest

Authentication

Include your supplier's API key in the x-api-key header. You can find this in the supplier detail page.

x-api-key: your_supplier_api_key

Request Body

Send a JSON body with the required system fields and any custom fields defined in your campaign's field mapping.

FieldTypeRequiredDescription
flo_campaign_idstringYesThe campaign ID to route this lead to.
flo_supplier_idstringYesThe supplier ID sending this lead.
first_namestringYesLead's first name.
last_namestringYesLead's last name.
phonestringYesLead's phone number.
emailstringYesLead's email address.
statestringNoTwo-letter US state code (used for state-based routing).
...custom fieldsvariesDependsAny additional fields defined in your campaign's field mapping.

Example Request

curl -X POST https://app.leaddistro.ai/api/v1/ingest \
  -H "Content-Type: application/json" \
  -H "x-api-key: your_supplier_api_key" \
  -d '{
    "flo_campaign_id": "campaign_abc123",
    "flo_supplier_id": "supplier_xyz789",
    "first_name": "John",
    "last_name": "Doe",
    "phone": "5551234567",
    "email": "john@example.com",
    "state": "TX"
  }'

Response

On success the API returns the created lead with its assigned buyer and status.

{
  "data": {
    "id": "lead_id",
    "status": "ACCEPTED",
    "buyer_id": "buyer_abc",
    "campaign_id": "campaign_abc123"
  }
}

If no buyer is available (all caps filled, no matching state filters, etc.), the lead status will be UNMATCHED instead of ACCEPTED.

Ping-Post Mode

For ping-post campaigns, use the separate ping endpoint to check buyer availability before committing the lead.

POST https://app.leaddistro.ai/api/v1/ping

The ping endpoint returns available buyers and their bid prices without creating a lead. You then post the full lead to the ingest endpoint with the chosen buyer.

Buyer Postback Webhook (conversion and lead updates)

Buyers (destinations) push updates on a delivered lead by posting back to the postback webhook. A CRM uses it to mark a lead converted or not qualified, set the conversion revenue, record the deal value, or add a note. The outcome is optional, so you can post revenue on a lead you have sold before its outcome is set (send at least one updatable field).

POST https://app.leaddistro.ai/api/webhooks/buyer-outcome

There is no /api/v1/outcome endpoint. Authenticate with the buyer's webhook secret in the X-Buyer-Secret header (generated in the destination's Postback Webhook settings; this is NOT the supplier x-api-key). A system that cannot set a custom header uses the Postback URL instead (below), which carries its own key in the address. The body can be JSON or a form (application/x-www-form-urlencoded or multipart/form-data). One buyer-level URL covers every campaign: the lead is matched from the body by lead_id (the UUID from the original delivery), by phone + campaign_id, by email + campaign_id, or by a custom campaign field such as a click ID (click_id + campaign_id, or match_field + match_value + campaign_id).

curl -X POST https://app.leaddistro.ai/api/webhooks/buyer-outcome \
  -H "Content-Type: application/json" \
  -H "X-Buyer-Secret: your_buyer_webhook_secret" \
  -d '{
    "lead_id": "<lead-uuid-from-the-original-delivery>",
    "outcome": "converted",
    "conversion_revenue": 200,
    "lead_value": 750,
    "note": "Signed retainer 2026-04-29",
    "idempotency_key": "crm-event-12345"
  }'
FieldTypeRequiredDescription
outcomeenumNoOne of pending, converted, not_qualified. Optional: send it to change the lead's status, or leave it out to update revenue, value, or a note only. Other values return 400.
lead_idstringOne matching pathLead UUID from the original delivery (preferred match).
phone / email + campaign_idstringOne matching pathAlternative match when lead_id was not stored.
click_id + campaign_idstringOne matching pathMatches the lead whose click_id field equals the value you send. Useful for affiliate flows where your buyer tracks clicks, not lead IDs. The campaign must have a click_id field.
match_field + match_value + campaign_idstringOne matching pathMatch by any other campaign field (for example transaction_id). The field must exist on the campaign; if the value matches more than one lead the request returns 409.
conversion_revenuenumberNoThe amount paid for this conversion. Sets the lead's revenue on converted and overrides the fixed per-conversion price on file. Also works on a lead that is already converted, so you can add or correct the revenue later. revenue is accepted as an alias.
lead_valuenumberNoThe buyer's own deal value, stored for reporting only. Never affects billing or revenue.
notestringNoFree-text reason, e.g. why a lead was not_qualified.
idempotency_keystringNoDedupes CRM retries.

To check what a CRM sent, open the lead and go to the Logs tab. The Postbacks section lists every postback for that lead, with the body that arrived, the reply we sent, and why it failed if it did. In the lead's History, click View request on an Outcome Received row to jump to it. A postback that matched no lead (wrong lead_id, or no lead with that phone) is on the Logs page instead: filter it to Outcome.

Postback URL (for systems that can only paste a URL)

Many CRMs, call trackers and affiliate platforms can only fire a URL: no custom header. For them, each destination has its own Postback URL with a key built into the address, so nothing else is needed to authenticate. Find it in the destination's Postback Webhook settings (the destination's ⋮ menu on the campaign, then Postback Webhook): click Generate Webhook Secret and the Postback URL (No Header) box appears with a copy button. Regenerating the secret changes the URL, and disabling the webhook turns it off.

GET or POST https://app.leaddistro.ai/api/webhooks/buyer-outcome/<key>?lead_id={lead_id}&outcome={outcome}&conversion_revenue={revenue}

It accepts every field the header version accepts, in the query string, a JSON body, or a form body (a body field wins over the same query field). Send outcome every time you want the status to change: firing the URL without one never marks anything converted. A lead then only takes the revenue, value or note you sent, and a call update with no outcome returns 400. call_revenue, payout and conversion_payout are read as conversion_revenue, and money like $1,250.00 is read as 1250. A value still left as a template token (such as {lead_id} or [tag:call_id]) returns 400 naming the field, so fix the mapping in the system that fires the URL. Keep the URL private: anyone with it can update that destination's leads.

Frequently Asked Questions

What is the Lead Distro AI ingest endpoint URL?
POST https://app.leaddistro.ai/api/v1/ingest. Authenticate with your supplier API key in the x-api-key header. Always required: flo_campaign_id and flo_supplier_id. Required by default: first_name, phone and email. last_name starts optional on a new campaign (older campaigns may still require it). Each campaign can turn these four on or off in its Fields tab, and its API docs list what that campaign needs. Add any custom fields defined in your campaign's field mapping. Response is JSON with the created lead's id, status, and assigned buyer_id.
How do I authenticate API requests to Lead Distro AI?
Include your supplier's API key in the x-api-key request header. Each supplier in Lead Distro AI gets a unique API key generated automatically on creation — find it on the supplier detail page. Keep the key server-side; never expose it in client-side JavaScript or commit it to public repositories. If a key is compromised, delete the supplier and create a new one to rotate.
What HTTP status codes does the ingest API return?
201 Created when the lead is accepted and distributed. 200 OK with status: UNMATCHED when the lead passes validation but no buyer is available. 400 Bad Request for missing required fields or invalid field formats. 401 Unauthorized when the API key is missing or invalid. 403 Forbidden when the supplier is not linked to the specified campaign, or when the source is paused (Source is paused; test leads still go through). 422 Unprocessable Entity when the lead fails campaign inbound filters or suppression checks. 429 Too Many Requests if you exceed the rate limit.
Are there rate limits on the ingest API?
Yes. Default limit is 100 requests per second per supplier API key, with burst allowance up to 200 RPS for 10 seconds. High-volume agencies can request higher limits — contact support. The ping endpoint has a separate, more generous limit since pings are lighter than full posts.
What's the difference between the ingest and ping endpoints?
Ingest creates a real lead record and triggers distribution to buyers. Ping is a pre-check that validates lead data against filters and buyer availability without creating a record — useful for ping-post campaigns where suppliers want to know if a lead will be accepted before sending the full data. A successful ping returns a signed ping_id token (valid 30 min) that the supplier includes in the subsequent ingest call as flo_ping_id.
Does the API support test mode?
Yes, in two ways. (1) Set the source to Test Mode on the campaign (right-click the source in the Sources table, or use the Status dropdown in Edit Source Settings): every ingest call from that source is then treated as a test lead with no payload changes required. (2) Or include test_lead: true in the ingest payload on a per-lead basis. Test leads run the full pipeline (field mapping, filters, routing) but deliver only to destinations that are also in Test Mode, carry $0 cost, and are excluded from billing, P&L reports, and Meta CAPI conversion events.
How does a buyer report a conversion or rejection back to Lead Distro AI?
POST https://app.leaddistro.ai/api/webhooks/buyer-outcome with the buyer's secret in the X-Buyer-Secret header. Body: outcome (pending, converted, or not_qualified), plus lead_id (or phone/email/click_id + campaign_id, or match_field + match_value + campaign_id) to match the lead. Optional conversion_revenue sets the exact revenue for a converted lead, lead_value records the buyer's own deal value for reporting, and note carries a rejection reason. There is no /api/v1/outcome endpoint.
My destination's CRM can only paste a URL and can't add a custom header. Can it still post outcomes back?
Yes. Use the destination's Postback URL, which has its key built into the address, so no X-Buyer-Secret header is needed. Open the destination's ⋮ menu on the campaign, choose Postback Webhook, click Generate Webhook Secret, and copy the Postback URL (No Header). It takes GET or POST, with fields in the query string, a JSON body, or a form body (application/x-www-form-urlencoded or multipart/form-data). Always send outcome (converted, not_qualified or pending): without it the lead's status does not change. No Zapier relay is needed.
How does the API handle duplicate leads?
Each campaign has a configurable duplicate detection window (default: 30 days). Duplicates are detected by phone, email, or custom fields you specify. Within the window, a duplicate is either rejected (status: DUPLICATE) or routed to the original buyer based on your campaign settings. Outside the window, duplicates are accepted as new leads.

If you have any questions, send us an email at support@leaddistro.ai