Traffic2Leads Partner API
Programmatically create and manage Traffic2Leads client accounts — visitor identification, lead caps, and lead delivery, provisioned in a single API call.
Overview
The Partner API lets approved Traffic2Leads partners provision client accounts under their own management. One POST /v1/accounts call creates the client account, its lead campaign, and its tracking pixel — with a monthly lead cap you control and, optionally, a webhook that delivers every identified lead straight to your systems.
- Scoped to you. Your API key sees and manages only the accounts you created — nothing else.
- Setup, not lead routing. Leads flow directly from the Traffic2Leads platform to each account's configured delivery (your webhook, or the account portal). The Partner API is the control plane.
- Billed from creation. Every account goes live on billing immediately — there is no trial mode. A
monthly_lead_capis required on every account, so spend is always bounded.
Authentication
Every request (except /healthz) requires your partner API key as a Bearer token:
Authorization: Bearer t2l_pk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Your key was issued to you by the Traffic2Leads team. Keep it server-side — never embed it in a browser or mobile app. If a key is compromised, contact us and we'll rotate it immediately.
Quickstart
Create a fully provisioned client account — pixel, caps, and webhook delivery — in one call:
curl -X POST https://partners.traffic2leads.ai/v1/accounts \
-H "Authorization: Bearer t2l_pk_XXXX..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: acme-2026-08-07-001" \
-d '{
"client_name": "Acme Roofing",
"client_email": "owner@acmeroofing.com",
"account_type": "B2C",
"monthly_lead_cap": 500,
"webhook_url": "https://your-platform.com/hooks/t2l-leads"
}'
const res = await fetch('https://partners.traffic2leads.ai/v1/accounts', {
method: 'POST',
headers: {
'Authorization': 'Bearer t2l_pk_XXXX...',
'Content-Type': 'application/json',
'Idempotency-Key': 'acme-2026-08-07-001',
},
body: JSON.stringify({
client_name: 'Acme Roofing',
client_email: 'owner@acmeroofing.com',
account_type: 'B2C',
monthly_lead_cap: 500,
webhook_url: 'https://your-platform.com/hooks/t2l-leads',
}),
});
const account = await res.json();
// SAVE account.portal_password NOW — it is returned exactly once.
Then place the returned pixel_code (or javascript_code) on the client's website, and identified visitors start arriving at your webhook. That's the whole integration.
portal_password — the client's login for https://login.traffic2leads.ai. It is not stored and cannot be retrieved again (it is only replayed within the 24-hour idempotency window). Capture it at creation time and deliver it to your client securely.
Create a client account
Creates the account, its lead campaign (active immediately), and its tracking pixel. Returns everything you need to onboard the client.
Request fields
| Field | Type | Description | |
|---|---|---|---|
client_name | string | REQUIRED | Your client's business name. A partner prefix is applied automatically to the account name. |
client_email | string | REQUIRED | The client's login email. Must not already exist on the platform — you'll get 409 duplicate_email if you've used it before. |
account_type | string | REQUIRED | "B2C" or "B2B" — the kind of lead identification. |
monthly_lead_cap | integer | REQUIRED | Max leads per month. Delivery stops at the cap and resumes on the reset day. |
daily_cap | integer | Max leads per day. | |
cap_reset_day | integer | Day of month (1–28) the monthly cap resets. | |
delivery_schedule | integer | Lead delivery frequency: 1=daily, 2=hourly, 3=every 30 min, 4=every 15 min, 5=every 5 min (default). | |
state_filters | string[] | Geo filter by US state, e.g. ["TX","OK"]. Mutually exclusive with zip_filters. | |
zip_filters | string[] | Geo filter by 5-digit ZIP. Mutually exclusive with state_filters. | |
webhook_url | string | HTTPS endpoint that receives every identified lead. See Webhook lead payload. | |
validate_only | boolean | Dry run: validates everything (including the duplicate-email check) and returns a preview — creates nothing and bills nothing. Use it while building your integration. |
Idempotency (recommended)
Send an Idempotency-Key header (any unique string, up to 128 chars) with every create. If your request times out and you retry with the same key within 24 hours, you get the original response back (marked with an Idempotency-Replayed: true header) instead of a second billed account.
Response 201
{
"account_id": 42,
"client_name": "SG — Acme Roofing",
"client_email": "owner@acmeroofing.com",
"account_type": "B2C",
"caps": { "monthly_lead_cap": 500, "daily_cap": null, "cap_reset_day": null },
"delivery_schedule": null,
"state_filters": null,
"zip_filters": null,
"status": "active",
"webhook_url": "https://your-platform.com/hooks/t2l-leads",
"pixel_code": "<img src='https://rdcdn.com/rt?aid=XXXXX&e=1&img=1' ... />",
"javascript_code": "<script> ... </script>",
"portal_password": "Xu2!example",
"created_at": "2026-08-07T18:31:02.558Z"
}
account_id is the ID you use on every other endpoint. Use pixel_code (image tag) or javascript_code (richer tracking) on the client's site — one of them, not both.
List your accounts
Returns every account you've created, newest first.
curl https://partners.traffic2leads.ai/v1/accounts \ -H "Authorization: Bearer t2l_pk_XXXX..."
const res = await fetch('https://partners.traffic2leads.ai/v1/accounts', {
headers: { 'Authorization': 'Bearer t2l_pk_XXXX...' },
});
const { accounts } = await res.json();
{
"accounts": [
{
"account_id": 42,
"client_name": "SG — Acme Roofing",
"client_email": "owner@acmeroofing.com",
"account_type": "B2C",
"caps": { "monthly_lead_cap": 500, "daily_cap": null, "cap_reset_day": null },
"delivery_schedule": null,
"state_filters": null,
"zip_filters": null,
"status": "active",
"webhook_url": "https://your-platform.com/hooks/t2l-leads",
"created_at": "2026-08-07T18:31:02.558Z"
}
]
}
Get one account
Same shape as the list entries, plus pixel_code and javascript_code so you can re-fetch the pixel any time. The portal_password is never included — it exists only in the create response.
Update account settings
Send any subset of the fields below — only what you send changes.
| Field | Notes |
|---|---|
monthly_lead_cap | New monthly cap. |
daily_cap | New daily cap. |
cap_reset_day | 1–28. |
delivery_schedule | 1–5 (see create). |
state_filters / zip_filters | Replaces the existing geo filters. Setting one type clears the other; you can't send both in one request. |
curl -X PATCH https://partners.traffic2leads.ai/v1/accounts/42 \
-H "Authorization: Bearer t2l_pk_XXXX..." \
-H "Content-Type: application/json" \
-d '{ "monthly_lead_cap": 1000, "state_filters": ["TX", "OK"] }'
await fetch('https://partners.traffic2leads.ai/v1/accounts/42', {
method: 'PATCH',
headers: {
'Authorization': 'Bearer t2l_pk_XXXX...',
'Content-Type': 'application/json',
},
body: JSON.stringify({ monthly_lead_cap: 1000, state_filters: ['TX', 'OK'] }),
});
Responds 200 with the full updated account. PATCH /v1/accounts/{id}/limits also exists as a caps-only alias (accepts just the three cap fields).
Set or replace the delivery webhook
Point the account's lead delivery at a (new) HTTPS endpoint at any time.
curl -X PUT https://partners.traffic2leads.ai/v1/accounts/42/webhook \
-H "Authorization: Bearer t2l_pk_XXXX..." \
-H "Content-Type: application/json" \
-d '{ "webhook_url": "https://your-platform.com/hooks/t2l-leads-v2" }'
await fetch('https://partners.traffic2leads.ai/v1/accounts/42/webhook', {
method: 'PUT',
headers: {
'Authorization': 'Bearer t2l_pk_XXXX...',
'Content-Type': 'application/json',
},
body: JSON.stringify({ webhook_url: 'https://your-platform.com/hooks/t2l-leads-v2' }),
});
Pause / resume lead delivery
POST /v1/accounts/{id}/pause stops lead collection for the account; POST /v1/accounts/{id}/activate resumes it. Use pause when a client offboards — there is no delete (contact us for permanent removal).
Usage — lead counts
Per-account lead counts for billing and reporting. Two modes:
?month=YYYY-MM— a calendar month (defaults to the current month if omitted)?start=YYYY-MM-DD&end=YYYY-MM-DD— any date range up to 366 days
curl "https://partners.traffic2leads.ai/v1/usage?start=2026-08-01&end=2026-08-31" \ -H "Authorization: Bearer t2l_pk_XXXX..."
const res = await fetch(
'https://partners.traffic2leads.ai/v1/usage?start=2026-08-01&end=2026-08-31',
{ headers: { 'Authorization': 'Bearer t2l_pk_XXXX...' } },
);
const usage = await res.json();
{
"start": "2026-08-01",
"end": "2026-08-31",
"accounts": [
{ "account_id": 42, "client_name": "SG — Acme Roofing", "lead_count": 137 },
{ "account_id": 43, "client_name": "SG — Bright Dental", "lead_count": 88 }
],
"total_leads": 225
}
Health check
No auth required. Returns {"status":"ok","db":"ok"} when the API is fully operational — useful for your monitoring.
Webhook lead payload
When an account has a webhook configured, each identified lead is delivered to your endpoint as an HTTP POST with a JSON body (Content-Type: application/json). Respond with a 2xx quickly; do your processing async. Fields:
| Field | Description |
|---|---|
FirstName / LastName | The identified visitor's name. |
Email | Verified email address. |
EmailHash | Stable hashed identifier for the contact. |
Address / Address2 / City / State / Zip | Postal address, when resolved. |
FirstPageViewUrl / LastPageViewUrl | First and most recent page the visitor viewed. |
PageViewUrls | Comma-separated list of pages viewed. |
TotalPageViews | Number of page views in the visit(s). |
InitialPageViewDate / LastPageViewDate | Timestamps of the first and last page views. |
ImpliedSecondsOnSite | Estimated time on site. |
VisitDetails | Additional visit attributes. |
CampaignId / CampaignName | The campaign that produced the lead (one per account). |
AudienceId / AudienceName | The pixel audience the lead came from. |
RecordId | Unique delivery record ID — use it to de-duplicate. |
SendDate | When the lead was queued for delivery. |
Errors & rate limits
Rate limit: 60 requests per minute per API key. Exceeding it returns 429 with a Retry-After header (seconds). All errors share one shape:
{ "error": { "code": "validation_error", "message": "monthly_lead_cap: monthly_lead_cap is required" } }
| HTTP | Code | Meaning |
|---|---|---|
| 400 | validation_error | A field failed validation — the message names it. |
| 400 | invalid_json | The request body isn't valid JSON. |
| 401 | unauthorized | Missing, malformed, or revoked API key. |
| 404 | not_found | The account doesn't exist — or isn't yours. |
| 409 | duplicate_email | You already created an account with this client_email. |
| 429 | rate_limited | Too many requests — honor Retry-After. |
| 502 | upstream_error | The platform rejected the operation; the message includes the reason. |
| 500 | internal_error | Unexpected error — contact us if it persists. |
Important notes
portal_password from the create response is the client's login for https://login.traffic2leads.ai; deliver it to them through your own channel. It is returned exactly once (plus the 24-hour idempotent replay window) and can never be retrieved afterward.
- Billing starts at creation. There is no trial mode. Caps are your spend control —
monthly_lead_capis required everywhere. - Password resets are self-serve at
login.traffic2leads.ai. Heads-up: the reset email arrives from a neutral platform domain (bit-sync.com), not a Traffic2Leads address. - No lead history over the API. Leads are delivered to the account's webhook (and visible in the account portal). The API reports counts, not lead records — so make your webhook endpoint reliable, and use
RecordIdto de-duplicate. - No delete endpoint. Pause an account to stop collection; contact us for permanent removal.
- Test with
validate_only— it exercises your full request, including duplicate detection, without creating a billed account.
Questions or a stuck integration? Contact your Traffic2Leads account manager.