---
title: "Create an offering"
method: POST
path: "/offerings"
tags: ["Offerings"]
---

# Create an offering

`POST /offerings`

Creates a new offering for the authenticated project. If the project has no offerings yet, the new one is auto-promoted to main (`tag` will be `1` in the response even if it was omitted in the request). Prefer `POST /v4/offerings/{offering_id}/set-main` over passing `tag=1` here when switching the main of an existing project.

## Headers

- `Idempotency-Key` string

## Request body

- V4OfferingCreate
  - `id` string, required — 1–64 chars of [a-zA-Z0-9._:\- ]. Spaces and colons are accepted for parity with dashboard-created offerings. Immutable after create.
  - `tag` 0 | null, nullable — Only `0` and `null` (or omitting the field) are accepted on create. `tag=1` is rejected with 400 `cannot_set_main_directly` — promote via `POST /v4/offerings/{offering_id}/set-main` (atomic). The very first offering in a project is auto-promoted to main even if `tag` is omitted.
  - `product_ids` string[] — Product UIDs in display order. Each must already exist in this project, otherwise the request fails with 400 `product_not_in_project`. Up to 100 entries per request (`maxItems`).

## Response `201`

Offering created.

- V4Offering
  - `object` 'offering', required
  - `id` string, required
  - `url` string, required
  - `tag` integer, nullable, required — Offering role within the project. `1` = main offering (`TAG_MAIN`) — exactly one offering per project has tag=1 at any time; promote via `POST /v4/offerings/{offering_id}/set-main`. `0` = regular offering that was demoted from main. `null` = regular offering that has never been tagged. Treat `0` and `null` as equivalent on read. The Offerings endpoints filter out experiment-variant offerings, but legacy rows could carry historical values other than `0`, `1`, or `null`, so the response field is intentionally not enum-restricted. Write schemas restrict accepted values server-side.
  - `product_ids` string[], required — Product UIDs that belong to this offering, in display order.
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required

## Other responses

- `400` — Invalid request body. Typed codes include `invalid_data` (schema validation failed), `invalid_product_id` (a `product_ids` entry is empty/too long/contains disallowed characters), `product_not_in_project` (a `product_ids` entry is not registered in the project), and `cannot_set_main_directly` (`tag: 1` was supplied — promote via `POST /offerings/{id}/set-main` instead).
- `401` — Missing or invalid authentication token.
- `409` — An offering with this `id` already exists.
- `415` — Unsupported Content-Type.
- `422` — Operation cannot be performed in the current state.
- `500` — Internal error

---

[API](https://skmtc.net/qonversion/apis/qonversion-rest-api-v4.md) · [All operations](https://skmtc.net/qonversion/apis/qonversion-rest-api-v4/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/qonversion/qonversion-rest-api-v4/versions/e3f72cf8951c/schema)
