---
title: "Upload offline conversions"
method: POST
path: "/api/v1/conversions"
tags: ["conversions"]
---

# Upload offline conversions

`POST /api/v1/conversions`

## Request

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

Reports conversions that happened off your website, such as a booked call or a signed contract, to the ad platform that produced the click, so the platform can credit the ad and learn from it. Send one conversion or a batch of up to 200.

Each conversion needs exactly one click id: `gclid`, `gbraid` or `wbraid` route to Google Ads, `msclkid` to Microsoft Advertising. `orderId` makes the upload idempotent: sending the same `orderId` twice records one conversion.

Also accepted with the `campaigns:write` scope.

**Errors**

- `400 VALIDATION_ERROR`: the body failed validation; `details.issues[]` names each field.

## Headers

- `X-Space-Id` string

## Request body

- union: One conversion, or `{ conversions: [...] }` with up to 200.
  - ConversionItem: One offline conversion. Provide exactly one click id: `gclid`, `gbraid` or `wbraid` for Google Ads, `msclkid` for Microsoft Advertising.
    - `gclid` string: Google Ads click id.
    - `gbraid` string: Google Ads click id for app campaigns on iOS.
    - `wbraid` string: Google Ads click id for web campaigns on iOS.
    - `msclkid` string: Microsoft Advertising click id.
    - `conversionAction` string, required: The conversion action's name or id, for example "Booked call".
    - `occurredAt` string, date-time, required: When the conversion happened (ISO 8601).
    - `value` number: Conversion value, optional.
    - `currency` string: ISO 4217 currency of `value`, optional.
    - `orderId` string: Idempotency key, for example your order or booking id. The same `orderId` is never counted twice.
    - `accountId` string: Upload to this connected ad account instead of the one inferred from the click id.
    - `platformId` 'google-ads' | 'microsoft-ads' | 'reddit-ads' | 'meta-ads' | 'openai-ads' | 'linkedin-ads': Upload to this platform instead of the one inferred from the click id.
  - object
    - `conversions` ConversionItem[], required
      - `gclid` string: Google Ads click id.
      - `gbraid` string: Google Ads click id for app campaigns on iOS.
      - `wbraid` string: Google Ads click id for web campaigns on iOS.
      - `msclkid` string: Microsoft Advertising click id.
      - `conversionAction` string, required: The conversion action's name or id, for example "Booked call".
      - `occurredAt` string, date-time, required: When the conversion happened (ISO 8601).
      - `value` number: Conversion value, optional.
      - `currency` string: ISO 4217 currency of `value`, optional.
      - `orderId` string: Idempotency key, for example your order or booking id. The same `orderId` is never counted twice.
      - `accountId` string: Upload to this connected ad account instead of the one inferred from the click id.
      - `platformId` 'google-ads' | 'microsoft-ads' | 'reddit-ads' | 'meta-ads' | 'openai-ads' | 'linkedin-ads': Upload to this platform instead of the one inferred from the click id.

## Response `200`

OK. The result is in `data`. List responses also carry `meta` with `nextCursor` and `total`.

- SuccessEnvelope: The shape of every successful response.
  - `data` unknown, required
  - `meta` object: Present on list responses.
    - `nextCursor` union: Pass as `cursor` to get the next page. `null` on the last page.
      - string
      - number
    - `total` integer: Number of items in this page.

## Other responses

- `201`: Created. The new resource is in `data`.
- `400`: The request is malformed or fails validation. `error.code` is `VALIDATION_ERROR` (with `details.issues[]` naming each field), `INVALID_REQUEST` (the body is not valid JSON or has the wrong shape), or one of the specific codes listed in this operation's description.
- `401`: The bearer token is missing, invalid, expired or revoked (`INVALID_TOKEN`).
- `403`: The token lacks the scope this operation needs (`INSUFFICIENT_SCOPE`), the plan is read-only (`READ_ONLY_MODE`), or the caller is not a member of the Space named in `X-Space-Id` (`NOT_A_MEMBER`).
- `404`: No such resource in the active Space (`NOT_FOUND`), or `X-Space-Id` names a Space that does not exist (`SPACE_NOT_FOUND`).
- `409`: The request conflicts with the current state, for example a delete blocked by dependents or a sync already running. This operation's description names the `error.code` values it can return.
- `429`: Too many requests (`RATE_LIMITED`). Wait for the number of seconds in the `Retry-After` header, then retry.

---

[API](https://skmtc.dev/growomat/apis/growomat-public-api.md) · [All operations](https://skmtc.dev/growomat/apis/growomat-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/growomat/apis/growomat-public-api/revisions/f02611b531aa?raw)
