curl -X POST "https://api.affonso.io/v1/signups" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"click_id": "ref_clk_xyz789",
"email": "jane@example.com",
"external_user_id": "user_42",
"name": "Jane Doe"
}'
const response = await fetch("https://api.affonso.io/v1/signups", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AFFONSO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
click_id: clickId,
email: "jane@example.com",
external_user_id: user.id,
}),
});
const { data } = await response.json();
console.log("Lead created:", data.id);
import os, requests
resp = requests.post(
"https://api.affonso.io/v1/signups",
headers={"Authorization": f"Bearer {os.environ['AFFONSO_API_KEY']}"},
json={
"click_id": click_id,
"email": "jane@example.com",
"external_user_id": str(user.id),
},
)
resp.raise_for_status()
print("Lead created:", resp.json()["data"]["id"])
{
"success": true,
"data": {
"id": "ref_clk_xyz789",
"affiliate_id": "aff_abc123",
"email": "jane@example.com",
"customer_id": null,
"subscription_id": null,
"status": "lead",
"name": "Jane Doe",
"metadata": null,
"created_at": "2026-01-25T11:55:00Z",
"converted_at": null
}
}
{
"success": true,
"data": {
"id": "ref_clk_xyz789",
"affiliate_id": "aff_abc123",
"email": "jane@example.com",
"status": "lead",
"name": "Jane Doe",
"created_at": "2026-01-25T11:55:00Z",
"converted_at": null
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "At least one of email or external_user_id is required",
"issues": {
"email": ["At least one of email or external_user_id is required"]
}
}
}
{
"success": false,
"error": {
"code": "CLICK_NOT_FOUND",
"message": "Click not found or does not belong to your team"
}
}
Signups
Record Lead Signup
Convert a previously tracked click into a lead. Server-side equivalent of the pixel.js Affonso.signup() call.
POST
/
v1
/
signups
curl -X POST "https://api.affonso.io/v1/signups" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"click_id": "ref_clk_xyz789",
"email": "jane@example.com",
"external_user_id": "user_42",
"name": "Jane Doe"
}'
const response = await fetch("https://api.affonso.io/v1/signups", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AFFONSO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
click_id: clickId,
email: "jane@example.com",
external_user_id: user.id,
}),
});
const { data } = await response.json();
console.log("Lead created:", data.id);
import os, requests
resp = requests.post(
"https://api.affonso.io/v1/signups",
headers={"Authorization": f"Bearer {os.environ['AFFONSO_API_KEY']}"},
json={
"click_id": click_id,
"email": "jane@example.com",
"external_user_id": str(user.id),
},
)
resp.raise_for_status()
print("Lead created:", resp.json()["data"]["id"])
{
"success": true,
"data": {
"id": "ref_clk_xyz789",
"affiliate_id": "aff_abc123",
"email": "jane@example.com",
"customer_id": null,
"subscription_id": null,
"status": "lead",
"name": "Jane Doe",
"metadata": null,
"created_at": "2026-01-25T11:55:00Z",
"converted_at": null
}
}
{
"success": true,
"data": {
"id": "ref_clk_xyz789",
"affiliate_id": "aff_abc123",
"email": "jane@example.com",
"status": "lead",
"name": "Jane Doe",
"created_at": "2026-01-25T11:55:00Z",
"converted_at": null
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "At least one of email or external_user_id is required",
"issues": {
"email": ["At least one of email or external_user_id is required"]
}
}
}
{
"success": false,
"error": {
"code": "CLICK_NOT_FOUND",
"message": "Click not found or does not belong to your team"
}
}
Use this endpoint when you want to record a lead signup from your own backend instead of relying on the browser pixel. The typical flow is:
- Track the click with
POST /v1/clicks— store the returnedidas yourclickId. - Once the visitor signs up in your application, call
POST /v1/signupswith thatclickIdplus their email and/or your internal user ID.
clickId returns the existing referral without creating duplicates.
If the affiliate’s program has a lead incentive configured, this call also creates the commission transaction and fires the transaction.created webhook in addition to referral.lead.
Body Parameters
string
required
The click ID returned by
POST /v1/clicks. Must belong to your team.string
The lead’s email address. Either
email or external_user_id must be provided. Silently ignored when the program has email tracking disabled.string
Your internal identifier for the lead (e.g. database user ID). Either
email or external_user_id must be provided.string
The lead’s display name. Maximum 255 characters. Silently ignored when the program has name tracking disabled.
Response
boolean
true on success. Returns false only on validation, auth, or not-found errors.object
The referral object after conversion.
Show Data Object Properties
Show Data Object Properties
string
Referral ID. Equal to the
click_id you passed — the same row is transitioned from click to lead.string
The affiliate user who owns this lead.
string | null
The lead’s email (omitted when the program disables email tracking).
string
lead after successful conversion. rejected if a fraud check (self-referral, disposable email, paid traffic) blocked the signup.string
ISO 8601 timestamp of when the click was originally recorded.
string | null
ISO 8601 timestamp of when the click was converted to a lead.
null for lead status (set later when status moves to customer/active).Status codes
| Code | Meaning |
|---|---|
201 Created | Click successfully converted to a lead. |
200 OK | Idempotent re-call — the click was already converted. Returns the existing referral. |
400 Bad Request | Validation error (missing click_id, neither email nor external_user_id provided, invalid email format). |
401 Unauthorized | Missing or invalid API key. |
404 Not Found | The click_id does not exist or belongs to a different team. |
429 Too Many Requests | Per-API-key rate limit exceeded. |
curl -X POST "https://api.affonso.io/v1/signups" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"click_id": "ref_clk_xyz789",
"email": "jane@example.com",
"external_user_id": "user_42",
"name": "Jane Doe"
}'
const response = await fetch("https://api.affonso.io/v1/signups", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AFFONSO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
click_id: clickId,
email: "jane@example.com",
external_user_id: user.id,
}),
});
const { data } = await response.json();
console.log("Lead created:", data.id);
import os, requests
resp = requests.post(
"https://api.affonso.io/v1/signups",
headers={"Authorization": f"Bearer {os.environ['AFFONSO_API_KEY']}"},
json={
"click_id": click_id,
"email": "jane@example.com",
"external_user_id": str(user.id),
},
)
resp.raise_for_status()
print("Lead created:", resp.json()["data"]["id"])
{
"success": true,
"data": {
"id": "ref_clk_xyz789",
"affiliate_id": "aff_abc123",
"email": "jane@example.com",
"customer_id": null,
"subscription_id": null,
"status": "lead",
"name": "Jane Doe",
"metadata": null,
"created_at": "2026-01-25T11:55:00Z",
"converted_at": null
}
}
{
"success": true,
"data": {
"id": "ref_clk_xyz789",
"affiliate_id": "aff_abc123",
"email": "jane@example.com",
"status": "lead",
"name": "Jane Doe",
"created_at": "2026-01-25T11:55:00Z",
"converted_at": null
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "At least one of email or external_user_id is required",
"issues": {
"email": ["At least one of email or external_user_id is required"]
}
}
}
{
"success": false,
"error": {
"code": "CLICK_NOT_FOUND",
"message": "Click not found or does not belong to your team"
}
}
Fraud checks
The same fraud checks that run for browser-side signups (self-referral, disposable email, paid traffic) also apply here. If any check is configured in BLOCK mode and rejects the signup:- The referral status is set to
rejectedinstead oflead. - The
referral.leadwebhook is not emitted. - No lead-incentive commission is created.
- The endpoint still returns
201 Createdwith the rejected referral object — inspectdata.statusto detect blocks.
Webhooks fired
| Event | When |
|---|---|
referral.lead | Conversion succeeded and was not blocked by fraud checks. |
transaction.created | Conversion succeeded, was not blocked, and the program has a lead incentive configured for this affiliate (via group incentive or override). |
Related endpoints
POST /v1/clicks— track the click that you’ll later convert.POST /v1/referrals— alternative endpoint when you want to skip the click stage and record a referral directly.
Was this page helpful?
