---
title: "Create a coupon"
method: POST
path: "/v1/coupons"
tags: ["Coupons"]
---

# Create a coupon

`POST /v1/coupons`

## Request

- Base URL: `https://api.yuvexpay.com`
- URL: `https://api.yuvexpay.com/v1/coupons`
- Auth: HTTP bearer
- TypeScript: <https://skmtc.dev/yuvexpay/apis/yuvexpay-api/docs/v1/coupons/post.ts> (a function with typed inputs; its response is checked against the schema)

Create a discount coupon. Requires the `coupons:write` scope. Apply it with `couponCode` on `POST /v1/payments`, or let the payer type it on the hosted checkout. Coupons belong to the environment of the key: a `ypk_test_` key manages sandbox coupons and a `ypk_live_` key production coupons, and a payment uses only coupons of its own environment.

## Headers

- `X-Idempotency-Key` string

## Request body

- CreateCouponRequest
  - `code` string, required: 3 to 32 characters from `A-Z`, `0-9`, `_` and `-`, after trimming. Stored uppercase, so `black10` is saved as `BLACK10`. Unique among the coupons of your account in this environment that are not deleted (`409 COUPON_CODE_TAKEN`).
  - `type` 'PERCENT' | 'FIXED', required: `PERCENT` requires `percentBp` and `FIXED` requires `amount`; sending the other field, or neither, returns `400 COUPON_VALUE_INVALID`.
  - `percentBp` integer: `PERCENT` only: the discount in basis points, `1` to `10000` (`10000` is 100%).
  - `amount` number: `FIXED` only: the discount in BRL, at most 2 decimal places.
  - `validFrom` string, date-time, nullable: ISO 8601 date-time with an offset or `Z`. Inclusive.
  - `validUntil` string, date-time, nullable: ISO 8601 date-time with an offset or `Z`. Exclusive. Must be after `validFrom` (`400 COUPON_WINDOW_INVALID`).
  - `maxRedemptions` integer, nullable: Total uses, counting payments holding the coupon and completed ones. Omitted or `null`: no limit.
  - `maxRedemptionsPerBuyer` integer, nullable: Uses per payer e-mail, checked when the e-mail is known. Omitted or `null`: no limit.
  - `productIds` string[]: Products of your account in this environment that the discount covers (`400 COUPON_PRODUCT_NOT_FOUND` otherwise). Empty: the whole order.
  - `active` boolean

## Response `201`

Coupon created.

- object
  - `coupon` Coupon, required
    - `id` string, uuid, required
    - `code` string, required: Uppercase code, 3 to 32 characters from `A-Z`, `0-9`, `_` and `-`.
    - `type` 'PERCENT' | 'FIXED', required
    - `percentBp` integer, nullable, required: `PERCENT` only: the discount in basis points, `1500` for 15% and `10000` for 100%. `null` on a `FIXED` coupon.
    - `amount` number, nullable, required: `FIXED` only: the discount in BRL. `null` on a `PERCENT` coupon.
    - `validFrom` string, date-time, nullable, required: The coupon works from this time on, inclusive. `null`: no start.
    - `validUntil` string, date-time, nullable, required: The coupon stops working at this time, exclusive. `null`: no end.
    - `maxRedemptions` integer, nullable, required: Total uses. `null`: no limit.
    - `maxRedemptionsPerBuyer` integer, nullable, required: Uses per payer e-mail. `null`: no limit.
    - `productIds` string[], required: Products the discount covers. Empty: the whole order.
    - `active` boolean, required
    - `redemptionCount` integer, required: Uses taken: payments holding the coupon that are still open, plus the completed ones. A payment that expires or is cancelled gives its use back.
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required

## Other responses

- `400`: Validation failed. Besides `VALIDATION_ERROR`: `COUPON_VALUE_INVALID`, `percentBp` and `amount` do not match `type`; `COUPON_WINDOW_INVALID`, `validUntil` is not after `validFrom`; `COUPON_PRODUCT_NOT_FOUND`, a `productIds` entry is not a product of your account in this environment.
- `401`: Missing or invalid authentication token.
- `403`: The API key is valid but does not have the required scope for this endpoint.
- `409`: `COUPON_CODE_TAKEN`: another coupon of your account in this environment that is not deleted has this code. A reused `X-Idempotency-Key` returns the flat idempotency errors instead.

## Changes

- **2026-10-31** `5236ef291a8e`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/yuvexpay/apis/yuvexpay-api/changes/v1/coupons/post.md)

---

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