Skip to content
LinkProfit

Conversions and Revenue

Attribute orders back to the click that produced them: the signed click identifier, the attribution window, goals, the server API, the browser script and outbound delivery.

Updated August 14, 2026

Conversion tracking closes the loop between a click and the money it produced. The redirector issues a signed identifier on every redirect; your server or your thank-you page sends it back with an order; every breakdown you already read gains a revenue column.

Conversions are a paid capability. When the plan does not include them the redirector stops issuing identifiers altogether, and both intake paths refuse conversions with a plan restriction.

The click identifier

On every redirect the worker issues a token and:

  • appends it to the destination address under a parameter name you choose (lp_cid by default);
  • writes it to a first-party cookie on your redirect domain, valid for 90 days.

The cookie is what makes attribution survive in browsers that no longer accept anything third-party — it is set by your own domain, not by ours.

The token is signed and bound to the tenant: the workspace and partner identifiers are part of the signed payload, so a token issued on one client's link is rejected in another client's workspace exactly like a forgery. It carries no personal data — the click moment, the link, the split variant, the country, the device class, the traffic source and a flag for suspicious traffic.

Both the parameter name and the on/off switch live in Conversions → Settings. Changing either rewrites the cached configuration of every link immediately.

The attribution window

A conversion that arrives later than the window is rejected with attribution_expired, a distinct code from invalid_click_id, so an integration can tell "too late" from "broken identifier" without guessing. The window is a per-workspace setting.

Goals

A goal is a named outcome: purchase, signup, trial. Goals may carry a default value and a currency, used when a conversion arrives without an amount. A goal referenced by a conversion that does not exist yet is created on first use, so an integration does not have to be configured in two places.

Sending conversions

From your server

curl -X POST https://api.linkprofit.com/v1/conversions \
  -H "Authorization: Bearer lp_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-10241" \
  -d '{
    "click_id": "1.eyJ1aWQiOiJ...",
    "goal": "purchase",
    "order_id": "10241",
    "amount_cents": 4999,
    "currency": "usd"
  }'

The key needs the conversions:write scope. Amounts are whole minimum units — cents, pence, kopecks. An amount of 49.99 is rejected with the field named rather than rounded silently, because a rounding rule invented in the middle of a payment path is how revenue reports quietly stop matching invoices.

From the browser

The worker serves a small script from your own redirect domain:

<script src="https://go.example.com/cv.js" defer></script>
<script>
  window.lpConversion({ goal: 'purchase', orderId: '10241', amountCents: 4999, currency: 'usd' });
</script>

The script reads the identifier from the URL or from the first-party cookie. There is no third-party host anywhere in the chain, which is both a privacy property and a white-label one: your client's page loads nothing that mentions the platform.

Duplicates

Deduplication is a single atomic insert, not a read followed by a write. Repeated deliveries of the same order_id create one conversion and return it marked as a duplicate — which is exactly what makes retrying a failed webhook safe rather than dangerous.

Suspicious conversions

The classifier's verdict travels inside the token, so a conversion attributed to a data centre or a proxy is marked as suspect when it is recorded. It appears in reports as its own segment rather than being deleted or silently mixed in. "Two hundred conversions" and "two hundred conversions, forty of them from one hosting range within an hour" are different facts.

Where conversions go next

  • A signed conversion.created webhook event is emitted through the normal webhook machinery: queue, signature, retry schedule, catch-up cron.
  • Configured advertising integrations receive the conversion through a delivery queue with an attempt counter incremented before the outbound call, a documented backoff and a give-up mark instead of infinite retries.

Monthly allowance

A plan may cap the number of conversions accepted per calendar month, counted in UTC. Past the cap, intake answers quota_exceeded — a distinct code from a plan restriction, so the difference between "not in your plan" and "used up this month" is visible without a support ticket.