Server attribution
Controlled rolloutReport conversions from your server.
Use scoped, hashed server keys, idempotency, optional HMAC signatures and replay protection to submit merchant-asserted affiliate conversions.
Create a conversion event
/api/v1/affiliate/conversionsControlled rolloutprogram_idUUIDrequiredPrivate affiliate program receiving the event.
eventstringrequiredMust match the rewarded event.
click_idUUIDExplicit LinkCode click attribution. Required unless promotion_code is supplied.
promotion_codestringFallback explicit attribution.
external_conversion_idstringrequiredUnique merchant order/conversion reference.
amount_minorintegerrequiredEligible monetary base in minor units.
payment_statusenumrequiredunknown, pending, paid, refunded, partially_refunded or chargeback.
occurred_atISO-8601requiredAuthoritative event time with timezone.
curl --request POST https://app.linkcode.co/api/v1/affiliate/conversions \
--header "Authorization: Bearer $LINKCODE_API_KEY" \
--header "Idempotency-Key: ORDER-123:purchase" \
--header "Content-Type: application/json" \
--data '{"program_id":"PROGRAM_UUID","event":"purchase","click_id":"CLICK_UUID","external_conversion_id":"ORDER-123","amount_minor":14900,"currency":"CAD","payment_status":"paid","occurred_at":"2026-07-28T15:00:00Z","test":false}'Authentication and scopes
API keys are shown once. LinkCode stores only the SHA-256 hash and a short prefix. Use the affiliate:conversions:write scope and restrict a key to one program whenever possible.
Optional or required HMAC
The exact raw body is signed with the API key. LinkCode rejects malformed signatures and timestamps outside the five-minute replay window.
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = createHmac("sha256", process.env.LINKCODE_API_KEY)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
headers["x-linkcode-timestamp"] = timestamp;
headers["x-linkcode-signature"] = `sha256=${signature}`;Idempotency and deduplication
Send a stable Idempotency-Key for every logical conversion. The database also enforces workspace + source + event + external_conversion_id uniqueness, so a double confirmation-page reload cannot double commission. Reusing a key or conversion ID with a different payload returns 409 idempotency_conflict.
Platform guidance
- ✓Stripe Checkout — report from a verified webhook after signature validation; pass lc_click_id through metadata.
- ✓Shopify — preserve lc_click_id in cart/order attributes and report from the server or approved webhook.
- ✓WooCommerce — store lc_click_id on the order and report after the relevant order status transition.
- ✓HTML/React — use the pixel only for pending browser-reported events.
- ✓Custom backends — use server API keys, idempotency and HMAC.
Test without financial side effects
Set test=true. Test events exercise validation and deduplication but never create production statistics, a payable commission or a settlement item.
Troubleshooting
401 unauthorizedauthMissing, invalid, revoked or expired key.
403 insufficient_scopescopeKey does not include affiliate:conversions:write or belongs to another program.
422 validation_failedpayloadInvalid type, missing attribution or non-integer amount.
409 idempotency_conflictdeduplicationA key or conversion ID was reused with a different payload.
429 rate_limitedretryRetry with exponential backoff and jitter.
duplicateidempotent successThe logical event was already accepted; do not create a new order ID.