# Merge a tag into another

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

`POST /v1/tags/{id}/merge`

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

Works with integration, agent and partner keys.

A repeat after success returns 404 or 409: treat that as done. [About idempotency](https://kirora.io/docs/api/reference/idempotency)

Moves every item carrying this tag onto `targetTagId`, then deletes this tag, in one step: how "BF" and "Black Friday" become one. An item already carrying both keeps one. Rules that name this tag (segments, campaign audiences, journey filters, goal populations, block conditions in designs) are pointed at the target in the same step, so a rule that named either tag now matches the items of both. Since that can change who a rule reaches, an agent key is refused with 403 `AGENT_KEY_REFUSED` when a rule names either tag. Merging a tag into itself is refused with 400.

## Path parameters

- `id` (string, required, uuid) — The tag'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.
- `Idempotency-Key` (string, optional, 8–255 characters) — Makes a retry safe: a repeat with the same key and body within 24 hours gets the first response again, with `Idempotency-Replay: true`. The same key with another request is 409 `IDEMPOTENCY_KEY_REUSED`; while the first is still running, 409 `IDEMPOTENCY_KEY_IN_USE`; after an `unsafe` first request failed or never returned, 409 `IDEMPOTENCY_KEY_OUTCOME_UNKNOWN`. Use a new key, such as a UUID, for each new request.

## Request body

- `targetTagId` (string, required, uuid) — The tag that takes over every item, and survives the merge.

## Returns

Returns `200 OK` with a `Tag` 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)
- `name` (string, required)
- `usage` (object, required) — How many items of each kind carry the tag.
  - `campaigns` (integer, required, min 0)
  - `journeys` (integer, required, min 0)
  - `segments` (integer, required, min 0)
  - `templates` (integer, required, min 0)
- `createdAt` (string, required, date-time)
- `updatedAt` (string, required, date-time)

Statuses:

- `200 OK`: The target tag, with its usage after the merge.
- `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`).

Headers on `200 OK`:

- `Idempotency-Replay` (string, optional, one of `true`) — `true` when this is the stored response to an earlier request with the same key.

## Example: Fold "BF" into "Black Friday"

```bash
curl -X POST https://api.kirora.io/v1/tags/018f2a4e-6b1c-7d3e-9f40-37386ae05a6b/merge \
  -H "Authorization: Bearer $KIRORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "targetTagId": "0192f3e0-1a2b-7c3d-8e4f-5a6b7c8d9e0f"
  }'
```

Response `200`:

```json
{
  "data": {
    "id": "0192f3e0-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
    "name": "Black Friday",
    "usage": {
      "campaigns": 6,
      "journeys": 1,
      "segments": 3,
      "templates": 3
    },
    "createdAt": "2026-10-01T09:30:00.000Z",
    "updatedAt": "2026-10-02T14:05:00.000Z"
  }
}
```
