Overview
The Lead Intake API lets external sources — landing pages, ad networks, affiliate platforms — push leads directly into the CRM and later query their first-time deposit (FTD) status.
Each API key is issued per integration. Contact the integration team to receive yours.
Submit Leads
POST /v1/leads
Validate, deduplicate & store
Check FTD Status
GET /v1/leads/{token}
Query deposit history
Unique Token
40-char SHA1 reference
returned on creation
Authentication
All /api/v1/* requests must carry a valid X-API-Key header.
Your API key will be provided to you by the integration team.
POST /api/v1/leads HTTP/1.1
Host: {{ request()->getHost() }}
X-API-Key: YOUR_API_KEY
Content-Type: application/json
Accept: application/json
?api_key=YOUR_KEY, but the header is preferred for security.
Rate Limiting
Endpoints are limited to 60 requests per minute per IP address. When exceeded the API returns HTTP 429.
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests per minute |
| X-RateLimit-Remaining | Requests remaining in the current window |
| Retry-After | Seconds to wait before retrying (only on 429) |
Error Format
All error responses share a consistent JSON structure:
| Field | Type | When present | Description |
|---|---|---|---|
| success | boolean | Always | Always false on errors |
| message | string | Always | Human-readable error description |
| errors | object | 422 only | Field-level validation details, key = field name |
| existing_by | string | 409 only | "email" or "phone" — which field duplicated |
| lead_token | string | 409 only | The 40-char token of the existing lead |
Endpoints
Creates a new lead in the CRM assigned to the office bound to the API key. Duplicates are detected by email and phone number. On success the response includes a 40-character SHA1 lead_token you can use later to query FTD status.
Request Body (JSON)
| Field | Type | Required | Validation | Description |
|---|---|---|---|---|
| fname | string | Required | max 100 | Lead's first name |
| lname | string | Required | max 100 | Lead's last name |
| string | Required | valid email, max 150 | Email address — used for duplicate detection | |
| phone | string | Required | /^\+?[1-9]\d{6,14}$/, max 30 |
International phone number (E.164), e.g. +14155550123. Used for duplicate detection. |
| country | string | Optional | max 100 | Lead's country name, e.g. Germany |
| aff_source_id | string | Optional | max 100 | Your affiliate / traffic-source identifier |
| funnel_name | string | Optional | max 150 | Landing page or funnel name the lead came from |
Responses
{{-- 201 --}}{
"success": true,
"message": "Lead accepted.",
"lead_token": "a3f7c2d19e4b0865f1234abcd5678901a2b3c4d5"
}
{
"success": false,
"message": "Lead already exists in the system.",
"existing_by": "email",
"lead_token": "a3f7c2d19e4b0865f1234abcd5678901a2b3c4d5"
}
{
"success": false,
"message": "Validation failed.",
"errors": {
"phone": ["Phone number is not valid. Use international format, e.g. +12125551234."],
"email": ["The email field is required."]
}
}
{ "success": false, "message": "Invalid API key." }
{ "message": "Too Many Attempts." }
Returns leads created within the inclusive date range for the office assigned to your API key. Each record reports whether the lead is a client and whether an approved deposit exists. Results are paginated and ordered by creation date.
Query Parameters
| Parameter | Required | Description |
|---|---|---|
| from | Yes | Start date in YYYY-MM-DD format. |
| to | Yes | End date in YYYY-MM-DD format; included in full. |
| page | No | Page number, default 1. |
| per_page | No | Records per page, default 100, maximum 500. |
| ftd | No | Use true to return only leads with an approved deposit, or false to return only leads without one. |
Example
curl -s "{{ url('/api/v1/leads') }}?from=2026-08-01&to=2026-08-31&ftd=true&per_page=100" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Accept: application/json"
{
"success": true,
"period": { "from": "2026-08-01", "to": "2026-08-31", "inclusive": true, "ftd": true },
"summary": { "total": 1, "ftd": 1, "without_ftd": 0, "clients": 1 },
"data": [
{
"id": 123,
"lead_token": "a3f7c2d19e4b0865f1234abcd5678901a2b3c4d5",
"fname": "Jane",
"lname": "Example",
"email": "jane@example.com",
"phone": "+61400000000",
"country": "Australia",
"status": "Client",
"is_client": true,
"ftd": true,
"ftd_amount": 500.00,
"aff_source_id": "campaign-42",
"funnel_name": "Sydney landing page",
"created_at": "2026-08-15 10:30:00"
}
],
"pagination": {
"current_page": 1,
"per_page": 100,
"last_page": 1,
"total": 2,
"next_page_url": null,
"previous_page_url": null
}
}
Returns the first-time deposit (FTD) status for a lead identified by its
40-character lead_token. An FTD is considered present when at least one
deposit with status approved exists for the lead.
Path Parameter
| Parameter | Type | Description |
|---|---|---|
| token | string (40 chars) | The SHA1 token returned by POST /v1/leads on creation |
Responses
{{-- 200 no FTD --}}{
"success": true,
"lead_token": "a3f7c2d19e4b0865f1234abcd5678901a2b3c4d5",
"ftd": false,
"ftd_amount": null
}
{
"success": true,
"lead_token": "a3f7c2d19e4b0865f1234abcd5678901a2b3c4d5",
"ftd": true,
"ftd_amount": 500.00
}
{ "success": false, "message": "Lead not found." }
{ "success": false, "message": "Invalid lead token format." }
Code Examples
{{-- cURL --}}cURL — Submit lead
curl -s -X POST "{{ url('/api/v1/leads') }}" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"fname": "John",
"lname": "Doe",
"email": "john.doe@example.com",
"phone": "+14155550123",
"country": "United States",
"aff_source_id": "fb_campaign_001",
"funnel_name": "crypto-lp-v3"
}'
cURL — Check FTD status
curl -s "{{ url('/api/v1/leads') }}/a3f7c2d19e4b0865f1234abcd5678901a2b3c4d5" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Accept: application/json"
PHP
<?php
function callApi(string $method, string $url, ?array $body, string $key): array {
$ch = curl_init($url);
$headers = ['X-API-Key: ' . $key, 'Accept: application/json'];
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
$headers[] = 'Content-Type: application/json';
if ($method === 'POST') curl_setopt($ch, CURLOPT_POST, true);
}
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return ['status' => $status, 'body' => json_decode($response, true)];
}
// ── Submit a lead ─────────────────────────────────────────────
$r = callApi('POST', '{{ url('/api/v1/leads') }}', [
'fname' => 'John',
'lname' => 'Doe',
'email' => 'john.doe@example.com',
'phone' => '+14155550123',
'country' => 'United States',
'aff_source_id' => 'fb_campaign_001',
'funnel_name' => 'crypto-lp-v3',
], 'YOUR_API_KEY');
if ($r['status'] === 201) {
$token = $r['body']['lead_token'];
echo "Lead accepted. Token: $token\n";
} elseif ($r['status'] === 409) {
$token = $r['body']['lead_token'];
echo "Duplicate ({$r['body']['existing_by']}). Existing token: $token\n";
} else {
echo "Error {$r['status']}: {$r['body']['message']}\n";
}
// ── Check FTD status ──────────────────────────────────────────
$r2 = callApi('GET', '{{ url('/api/v1/leads') }}/' . $token, null, 'YOUR_API_KEY');
if ($r2['body']['ftd']) {
echo "FTD confirmed! Amount: " . $r2['body']['ftd_amount'] . "\n";
} else {
echo "No FTD yet.\n";
}
JavaScript (fetch)
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = '{{ url('/api/v1') }}';
// ── Submit a lead ─────────────────────────────────────────────
async function submitLead(lead) {
const res = await fetch(`${BASE_URL}/leads`, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify(lead),
});
const data = await res.json();
if (res.status === 201) {
console.log('Accepted. Token:', data.lead_token);
return data.lead_token;
}
if (res.status === 409) {
console.warn('Duplicate by', data.existing_by, '— token:', data.lead_token);
return data.lead_token;
}
throw new Error(`Error ${res.status}: ${data.message}`);
}
// ── Check FTD status ──────────────────────────────────────────
async function checkFtd(token) {
const res = await fetch(`${BASE_URL}/leads/${token}`, {
headers: { 'X-API-Key': API_KEY, 'Accept': 'application/json' },
});
const data = await res.json();
return data; // { ftd: true/false, ftd_amount: N | null }
}
// ── Usage ─────────────────────────────────────────────────────
const token = await submitLead({
fname: 'John',
lname: 'Doe',
email: 'john.doe@example.com',
phone: '+14155550123',
country: 'United States',
aff_source_id: 'fb_campaign_001',
funnel_name: 'crypto-lp-v3',
});
const ftdStatus = await checkFtd(token);
console.log(ftdStatus.ftd ? `FTD: $${ftdStatus.ftd_amount}` : 'No FTD yet');
Python (requests)
import requests
API_KEY = 'YOUR_API_KEY'
BASE_URL = '{{ url('/api/v1') }}'
HEADERS = {'X-API-Key': API_KEY, 'Accept': 'application/json'}
# ── Submit a lead ─────────────────────────────────────────────
r = requests.post(
f'{BASE_URL}/leads',
headers=HEADERS,
json={
'fname': 'John',
'lname': 'Doe',
'email': 'john.doe@example.com',
'phone': '+14155550123',
'country': 'United States',
'aff_source_id': 'fb_campaign_001',
'funnel_name': 'crypto-lp-v3',
}
)
data = r.json()
token = None
if r.status_code == 201:
token = data['lead_token']
print(f'Accepted. Token: {token}')
elif r.status_code == 409:
token = data['lead_token']
print(f"Duplicate by {data['existing_by']}. Existing token: {token}")
else:
print(f"Error {r.status_code}: {data['message']}")
exit(1)
# ── Check FTD status ──────────────────────────────────────────
r2 = requests.get(f'{BASE_URL}/leads/{token}', headers=HEADERS)
data2 = r2.json()
if data2['ftd']:
print(f"FTD confirmed! Amount: {data2['ftd_amount']}")
else:
print('No FTD yet.')
Lead Intake API — {{ config('app.name') }} — v1 — Contact Admin