# Change a conversion goal

Source: https://kirora.io/docs/api/reference/updateConversionGoal

`PATCH /v1/conversion-goals/{id}`

Requires an API key with the `conversion-goals:write` scope. [About keys and scopes](https://kirora.io/docs/api/reference/authentication)

Works with integration, agent and partner keys.

Safe to retry: a repeat sets the same values again. [About idempotency](https://kirora.io/docs/api/reference/idempotency)

Changes the attribution window, value property or currency for events processed from now on; conversions already counted keep their attribution and value, and are not counted again under the new window. Changing the window sets `windowChangedAt`, so a reader can tell the all-time totals mix both. Clearing `valueProperty` clears `currency` too. The event and its filter cannot change: create another goal.

## Path parameters

- `id` (string, required, uuid) — The conversion goal's id.

## Header parameters

- `Kirora-Workspace` (string, optional, pattern `^[A-Za-z0-9._:-]{1,128}$`) — Partner keys only: the child workspace to act in, by the external id the partner gave it. Without it, a partner key acts in its own workspace. Any other key that sends it is refused with 403, and an unknown workspace is 404.

## Request body

- `attributionWindow` (DurationInput, optional) — How long after a message the event still counts: 1 to 3,650 whole days.
  - `value` (integer, required, min > 0)
  - `unit` (string, required, one of `seconds`, `minutes`, `hours`, `days`)
- `valueProperty` (string | null, optional, 1–64 characters)
- `currency` (string | null, optional, pattern `^[A-Z]{3}$`)

## Returns

Returns `200 OK` with a `ConversionGoal` in `data`. It can also return `409 Conflict`, `413 Payload Too Large` or `415 Unsupported Media Type`; see the statuses below. Otherwise returns an error; [Errors](https://kirora.io/docs/api/reference/errors) lists every code and which to retry.

- `id` (string, required, uuid)
- `campaignId` (string | null, required, uuid) — The campaign it measures.
- `journeyId` (string | null, required, uuid) — The journey it measures.
- `eventName` (string, required) — The event that counts as a conversion.
- `where` (object[] | null, required, at least 1 item, at most 5 items) — Property conditions the event must meet; `null` counts every one.
  - `property` (string, required, 1–64 characters) — The event property key.
  - `operator` (string, required, one of `equals`, `notEquals`, `gt`, `gte`, `lt`, `lte`) — `notEquals` also matches an event without the property. `equals` and `notEquals` compare the property as text, ignoring case and accents.
  - `value` (string, required, up to 255 characters) — What to compare with, as text (`"pro"`, `"true"`); a number (`"50"`) for `gt`, `gte`, `lt` and `lte`.
- `occurrence` (string | null, required, one of `first`, `repeat`) — `first`: only the contact's first event of this name; `repeat`: any after it; `null`: every one.
- `attributionWindow` (Duration, required) — How long after a message the event still counts, in days.
  - `value` (integer, required, min > 0)
  - `unit` (string, required, one of `seconds`, `minutes`, `hours`, `days`)
- `windowChangedAt` (string | null, required, date-time) — When the attribution window was last changed; `null` if never. A change applies to events processed after it: conversions counted before keep the window they were counted under.
- `valueProperty` (string | null, required) — The event property summed as revenue; `null` counts no value.
- `currency` (string | null, required) — The revenue's currency, if named.
- `countedFrom` (string, required, date-time) — The earliest events the goal can count: when it was created, the start of the event history then retained. Events from then on are matched to the sends before them, those tracked before the goal existed included; older ones are gone.
- `createdAt` (string, required, date-time)

Statuses:

- `200 OK`: The goal as changed.
- `409 Conflict`: The request conflicts with current state — a duplicate unique value, or a resource whose status does not allow this operation.
- `413 Payload Too Large`: The body is larger than this operation accepts (`PAYLOAD_TOO_LARGE`).
- `415 Unsupported Media Type`: The body is not JSON, or not the upload the operation takes (`UNSUPPORTED_MEDIA_TYPE`).

## Example: Credit orders up to a week after a message

```bash
curl -X PATCH https://api.kirora.io/v1/conversion-goals/018f2a4e-6b1c-7d3e-9f40-37386ae05a6b \
  -H "Authorization: Bearer $KIRORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "attributionWindow": {
      "value": 7,
      "unit": "days"
    }
  }'
```

Response `200`:

```json
{
  "data": {
    "id": "0192f3d0-7a1b-7c2d-8e3f-4a5b6c7d8e9f",
    "campaignId": null,
    "journeyId": "0192f3a4-3d5e-7a7f-8c43-6b8c9d0e1f2a",
    "eventName": "Order Completed",
    "where": null,
    "occurrence": null,
    "attributionWindow": {
      "value": 7,
      "unit": "days"
    },
    "windowChangedAt": "2026-10-08T10:15:00.000Z",
    "valueProperty": "total",
    "currency": "USD",
    "countedFrom": "2026-07-03T09:30:00.000Z",
    "createdAt": "2026-10-01T09:30:00.000Z"
  }
}
```
