# Discounts

Discount codes let you run promotions: a flat amount off, or a percentage off,
redeemable at checkout. This guide covers the full lifecycle — create, list,
retrieve, update, and delete — and how a code is applied when a customer buys a
ticket.

## Scopes

Every discount endpoint requires the **`events:write`** scope.

| Endpoint | Method | Scope |
| --- | --- | --- |
| `/v1/discounts` | `POST` | `events:write` |
| `/v1/discounts` | `GET` | `events:write` |
| `/v1/discounts/{id}` | `GET` | `events:write` |
| `/v1/discounts/{id}` | `PATCH` | `events:write` |
| `/v1/discounts/{id}` | `DELETE` | `events:write` |

## The discount object

```json
{
  "id": "64fa1b2c9e7d654321fedcba",
  "code": "SUMMER10",
  "type": "percentage",
  "value": 10,
  "max_uses": 500,
  "used_count": 0,
  "expires_at": "2026-09-01T00:00:00.000Z",
  "active": true,
  "created_at": "2026-06-05T12:00:00.000Z"
}
```

| Field | Meaning |
| --- | --- |
| `code` | The string the customer types at checkout. If you omit it on create, one is generated for you. |
| `type` | `"fixed"` or `"percentage"`. |
| `value` | For `fixed`, the amount off in your currency. For `percentage`, a number from `0`–`100`. |
| `max_uses` | Total redemptions allowed across all customers (`null` = unlimited). |
| `used_count` | How many times it's been redeemed so far. |
| `expires_at` | When it stops working (`null` = no expiry). |
| `active` | Whether it's currently usable. |

## Create a percentage discount

`value` is a percentage between 0 and 100. The example below is 10% off, capped
at 500 redemptions, expiring on a fixed date.

```bash
curl https://api.ticketconnect.example/v1/discounts \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "code": "SUMMER10",
    "type": "percentage",
    "value": 10,
    "max_uses": 500,
    "expires_at": "2026-09-01T00:00:00.000Z"
  }'
```

```json
{
  "id": "64fa1b2c9e7d654321fedcba",
  "code": "SUMMER10",
  "type": "percentage",
  "value": 10,
  "max_uses": 500,
  "used_count": 0,
  "expires_at": "2026-09-01T00:00:00.000Z",
  "active": true,
  "created_at": "2026-06-05T12:00:00.000Z"
}
```

## Create a fixed-amount discount

For a `fixed` discount, `value` is an amount in your settlement currency. This is
$15 off:

```bash
curl https://api.ticketconnect.example/v1/discounts \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "code": "WELCOME15",
    "type": "fixed",
    "value": 15
  }'
```

```json
{
  "id": "64fa77c1e9b7d654321fedcb",
  "code": "WELCOME15",
  "type": "fixed",
  "value": 15,
  "max_uses": null,
  "used_count": 0,
  "expires_at": null,
  "active": true,
  "created_at": "2026-06-05T12:05:00.000Z"
}
```

> **Note:** You can scope a code to a single event by passing its id in the `event_ids`
> array on create (only the first entry is used — one code, one event). Omit it
> for an account-wide code. If you don't pass a `code`, the API generates a
> unique one (e.g. `DISC-A1B2C3D4E5F6`) and returns it. Codes are matched
> **uppercase** at redemption, so create codes in uppercase.


## How discounts apply at checkout

A discount changes the amount your customer pays — nothing more:

* The customer enters the `code` at checkout.
* The platform validates it — active, not expired, under `max_uses`, not already
  redeemed by that customer (each customer can use a given code once), and
  applicable to the event — and applies it to the order.
* A `percentage` code subtracts that percentage from the order total. `fixed`
  codes can be created and managed through the API, but checkout currently
  applies percentage codes only.
* The amount is always recomputed **server-side** from the event/tier price — a
  client can never dictate the final price — and `used_count` is incremented on
  redemption.

> **Warning:** Amounts are server-authoritative. The discount only adjusts the order total the
> platform calculates; you never send a final price from the client.


## List discounts

Cursor-paginated via `limit` (and `starting_after`).

```bash
curl "https://api.ticketconnect.example/v1/discounts?limit=20" \
  -H "Authorization: Bearer sk_test_..."
```

## Retrieve a discount

```bash
curl https://api.ticketconnect.example/v1/discounts/64fa1b2c9e7d654321fedcba \
  -H "Authorization: Bearer sk_test_..."
```

## Update a discount

`PATCH` accepts `value`, `max_uses`, `expires_at`, and `active`. (To deactivate a
code without deleting it, set `active: false`.) The `value` is validated against
the discount's existing type — a percentage still must be 0–100.

```bash
curl https://api.ticketconnect.example/v1/discounts/64fa1b2c9e7d654321fedcba \
  -X PATCH \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "max_uses": 1000,
    "active": false
  }'
```

The full updated discount object is returned.

## Delete a discount

```bash
curl https://api.ticketconnect.example/v1/discounts/64fa1b2c9e7d654321fedcba \
  -X DELETE \
  -H "Authorization: Bearer sk_test_..."
```

```json
{ "id": "64fa1b2c9e7d654321fedcba", "deleted": true }
```

A missing or non-owned id returns `404` with a `resource_missing` error on any of
the retrieve/update/delete operations.

## See also

* [Webhooks](#webhooks) — `payment.succeeded` fires on a completed checkout.
* [API reference](#api-overview) — full endpoint details.
