POST
Conversion postback
Report a conversion for a Buzz Links session. The server resolves the link from session_id (last qualified click). Do not send link_id.
Endpoint
POST${BASE_URL}/user/conversions/postback
Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | required | application/json |
| X-Buzz-Key | required | Project API key id for this campaign |
| X-Buzz-Timestamp | required | Unix seconds. Same ±300s window as in-app webhooks |
| X-Buzz-Signature | required | HMAC over trim(timestamp) + "\n" + sha256hex(canonicalJSON(body)) |
Request body
| Field | Type | Description |
|---|---|---|
| idempotency_key | string | Non-empty. Unique per campaign for deduplication — safe for retries |
| session_id | string | Non-empty. Must match an attributed Buzz Links session |
| campaign_id | integer | Must match the API key's campaign and the attributed session's campaign |
| conversion_code | string | Max 64 chars. Must match an active conversion type (and destination rules where applicable) |
| metadata | object | optional Serialized JSON up to 8 KB |
Capture
session_id from the Buzz Link flow on the client and send it from your backend with the postback. If the session is unknown or never had a qualified click, the conversion is unattributed.Complete example
const body = {
idempotency_key: 'order_' + Date.now(),
session_id: SESSION_ID,
campaign_id: CAMPAIGN_ID,
conversion_code: 'signup_complete',
metadata: { plan: 'pro' },
};
const ts = Math.floor(Date.now() / 1000);
const signature = signRequest(PROJECT_SECRET, ts, body);
const res = await fetch(`${BASE_URL}/user/conversions/postback`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Buzz-Key': PROJECT_KEY_ID, // Note: X-Buzz-Key, not X-Buzz-Key-Id
'X-Buzz-Timestamp': String(ts),
'X-Buzz-Signature': signature,
},
body: JSON.stringify(body),
});Success response
{
"status": 200,
"message": "Success !",
"data": {
"success": true,
"received": true,
"message": "Conversion accepted; processing in background. Use idempotency_key for idempotency.",
"conversion_event_id": null
}
}Responses
200Accepted.
data.received === true. Qualification and points decided asynchronously.400Validation failure — missing fields, bad
campaign_id, or metadata over 8 KB.403Postback disabled, invalid/revoked key, signature failure, timestamp window exceeded, or campaign mismatch.
429Rate limit exceeded (60 req/min per key).
Use a stable
idempotency_key per business event so retries never double-count.