---
title: "Report a conversion"
method: POST
path: "/api/v1/conversions"
tags: ["Conversions"]
---

# Report a conversion

`POST /api/v1/conversions`

Report a conversion — a purchase, signup, or custom event that happened on your site after someone clicked a Linkly link.

Pass the `linkly_cid` your landing page captured to attribute the conversion to the originating link. A missing or unrecognised `linkly_cid` is not an error: the conversion is recorded unattributed rather than dropped.

### Leads and sales

Set `event_type` to `lead` for signups, trials and demo requests, `sale` when money changes hands, or `custom` for anything else. The type drives the clicks → leads → sales funnel.

Send `external_id` — your own customer identifier — on every event. A `lead` reported with both an `linkly_cid` and an `external_id` ties that customer to the link, and later events for the same `external_id` inherit the attribution automatically. This is what makes server-side sales attributable: the purchase usually arrives from a billing webhook that never saw the `linkly_cid`. Attribution is first-touch, so a customer who later arrives via a different link keeps the credit on their original one.

Supply `event_id` to make the call idempotent. Reporting the same `event_id` twice returns `200` with the original conversion instead of creating a duplicate, so a retrying client is safe.

## Request body

- object — A conversion to record
  - `amount_cents` integer — Value in the smallest currency unit. May be negative to record a refund or chargeback, which nets against earlier revenue.
  - `country` string — Two-letter country code for the conversion. Inferred for browser-side calls; supply it explicitly from a server-side integration, where the connecting address is your own infrastructure rather than the customer's.
  - `currency` string — ISO 4217 currency code. Defaults to USD.
  - `event_id` string — Your identifier for this event. Used as an idempotency key — reporting the same value twice will not create a second conversion. Applies to any event type, not just purchases.
  - `event_name` string, required — What happened, e.g. `purchase`, `signup`, `trial_started`
  - `event_type` 'lead' | 'sale' | 'custom' — Coarse type driving the funnel. `lead` establishes customer identity, `sale` records revenue. Defaults to `custom`.
  - `external_id` string — Your identifier for the customer. Send it on every event: it is what links a later server-side sale back to the click that produced the signup.
  - `linkly_cid` string — The attribution token captured from the landing page URL. Omit if unavailable — the conversion is then recorded without a link attribution.
  - `metadata` object — Arbitrary JSON, up to 10,000 bytes encoded.
  - `occurred_at` string, date-time — When the conversion happened. Defaults to now.
  - `visitor_ip` string — The end customer's IP, when your server has it. Omit unless you do — for server-side calls Linkly otherwise records the connecting address as your server, not the customer, and excludes it from geographic reporting. Sending this asserts you have a lawful basis to share it. Never returned by the API.

## Response `200`

Already recorded — the existing conversion for this event_id

- object
  - `amount_cents` integer, nullable
  - `click_id` string, nullable
  - `country` string, nullable
  - `currency` string, nullable
  - `event_id` string, nullable
  - `event_name` string
  - `event_type` string
  - `external_id` string, nullable
  - `id` string — ULID. Sorts chronologically, so ids are ordered by creation.
  - `inserted_at` string, date-time
  - `ip_source` 'visitor' | 'server' | 'unknown' — Whose address was recorded. `server` means the connecting address belonged to your backend or a platform relay, so it is excluded from geographic reporting. The address itself is never returned.
  - `link_id` integer, nullable — The attributed link, or null if the conversion could not be attributed.
  - `metadata` object, nullable
  - `occurred_at` string, date-time
  - `source` string — Which integration reported it.

## Other responses

- `201` — Conversion recorded
- `400` — Invalid parameters
- `401` — Unauthorized
- `403` — Not available on your plan
- `422` — Validation failed

---

[API](https://skmtc.net/linklyhq/apis/linkly-url-shortener-api.md) · [All operations](https://skmtc.net/linklyhq/apis/linkly-url-shortener-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/linklyhq/linkly-url-shortener-api/revisions/351c1f004617/schema)
