---
title: "Record a conversion"
method: POST
path: "/conversions"
tags: ["Conversions"]
---

# Record a conversion

`POST /conversions`

## Request

- Base URL: `https://api.supersendtx.com`
- URL: `https://api.supersendtx.com/conversions`
- Auth: HTTP bearer

Idempotent on `(goal, external_id)` — send the same `external_id` twice
and the second call returns the first conversion with `duplicate: true`,
so a retried webhook can never double-count.

Identify the person with whichever of `click_id`, `contact_id`, or
`email` you have. `click_id` is the `stx_cid` value carried on links in
campaign email and stored by the tracking script; it is the strongest
signal and skips the lookup entirely. Recording a conversion never
creates a contact.

Omit `goal` to use the account's primary goal.

## Request body

- CreateConversionRequest: Identify the person with at least one of `click_id`, `contact_id`, or `email`.
  - `goal` string: Goal key. Defaults to the account's primary goal.
  - `goal_id` string
  - `click_id` string: The `stx_cid` value carried on campaign links.
  - `contact_id` string
  - `email` string, email
  - `value_cents` integer: Amount in minor units (cents). Defaults to the goal's default value. Ignored (stored as 0) on count-only goals: `visit`, `feedback`, `waitlist`, `qualify`. Named `value_cents` so `49` cannot be mistaken for $49.
  - `currency` string: 3-letter ISO code. Defaults to the goal's currency.
  - `external_id` string: Your own id for this conversion (charge id, order number). Makes the call idempotent for the goal.
  - `occurred_at` string, date-time: Defaults to now. Attribution is measured back from this time.

## Response `200`

Conversion recorded, or an existing one returned unchanged

- ConversionResponse
  - `conversion` Conversion, required
    - `id` string, required
    - `goal_id` string, required
    - `contact_id` string, nullable, required: Null when no contact matched; the email is kept either way.
    - `email` string, email, nullable, required
    - `value_cents` integer, required: Minor units of `currency`. Always 0 unless the goal is `revenue` (`visit`, `feedback`, `waitlist`, and `qualify` are count-only).
    - `currency` string, required
    - `external_id` string, nullable, required
    - `source` 'api' | 'script' | 'event', required
    - `occurred_at` string, date-time, required
    - `attributed_campaign_id` string, nullable, required
    - `attributed_variant_id` string, nullable, required
    - `attributed_recipient_id` string, nullable, required
    - `attributed_automation_id` string, nullable, required: The automation credited with the conversion, when the winning touch was an email that automation sent. Null otherwise (including when a campaign is credited).
    - `attributed_run_id` string, nullable, required: The automation run that sent that email. Null unless `attributed_automation_id` is set.
    - `attribution_kind` 'click' | 'open' | 'send' | 'none', required: How the conversion was tied to a campaign or automation, strongest first. Reported so you can discount weak attribution rather than treat every conversion as earned: `click` came from a click id or a clicked email, `open` and `send` from the last campaign or automation email that reached the person inside the goal's window, and `none` means the conversion is unattributed.
    - `ad_gclid` string, nullable, required: Google Ads click id (`gclid`) tied to the conversion: the ad click the tracking script saw in the browser when it reported the conversion, otherwise the ad click that first brought the contact in. Null when there is none.
    - `ad_gbraid` string, nullable, required: Google Ads `gbraid` click id, used instead of `gclid` for iOS app-to-web clicks. Same sourcing as `ad_gclid`.
    - `ad_wbraid` string, nullable, required: Google Ads `wbraid` click id, used instead of `gclid` for web-to-web clicks where no cross-site identifier can be set. Same sourcing as `ad_gclid`.
    - `created_at` string, date-time, required
  - `duplicate` boolean, required: True when this `external_id` was already recorded for the goal — the existing conversion is returned unchanged and nothing was written.

## Other responses

- `400`: Invalid request
- `401`: Missing or invalid API key
- `404`: Conversion goal not found, and no primary goal is configured

---

[API](https://skmtc.dev/ranla/apis/supersend-tx-api.md) · [All operations](https://skmtc.dev/ranla/apis/supersend-tx-api/llms.txt) · [OpenAPI document](https://skmtc.dev/ranla/apis/supersend-tx-api/revisions/e3e782652f50?raw)
