# Discount codes API

> Create and deactivate discount codes with the Anytime Capital Payments API: a percentage or amount off, with an optional use limit and expiry date.

Source: https://anytime-capital.com/docs/discount-codes · Markdown: https://anytime-capital.com/docs/discount-codes.md · All docs: https://anytime-capital.com/docs/llms-full.txt

Codes customers enter at checkout on payment links that allow them (`allowDiscountCodes`): a percentage or a fixed amount off the subtotal, with an optional limit on uses and an expiry. Codes are stored upper case and are unique per business. Add `?code=FALL15` to a link's `url` to apply one when checkout opens.

| Topic | Detail |
| --- | --- |
| Endpoints | [`POST /api/v1/discount-codes`](#create-discount-code), [`GET /api/v1/discount-codes`](#list-discount-codes), [`GET /api/v1/discount-codes/{id}`](#get-discount-code), [`POST /api/v1/discount-codes/{id}/deactivate`](#deactivate-discount-code) |
| Key permissions | `discount_codes:write`, `discount_codes:read` |
| Samples | curl; Node.js 18+ with the built-in `fetch` (in an ES module); the [Node SDK](https://anytime-capital.com/docs/node-sdk.md) (preview: not on npm yet); Python with `requests`. |
| Every request can also answer | 401 `UNAUTHORIZED`, 401 `API_KEY_EXPIRED`, 403 `NOT_ENROLLED`, 403 `PERMISSION_DENIED`, 403 `IP_NOT_ALLOWED`, 429 `RATE_LIMITED`, 500 `INTERNAL_ERROR`. See [Error codes](https://anytime-capital.com/docs/error-codes.md). |

> **On subscriptions:** Whether a code also works on subscription plans, for how many payments, and for new customers only, is set in the dashboard on the **Discounts** page. See [Subscription discounts](https://anytime-capital.com/docs/subscription-discounts.md).

## The discount code object

```json
{
  "object": "discount_code",
  "livemode": true,
  "id": "dc_311",
  "code": "FALL15",
  "percentOffBps": 1500,
  "amountOffCents": null,
  "maxRedemptions": 100,
  "redemptions": 12,
  "expiresAt": "2026-11-30T23:59:59.000Z",
  "status": "active",
  "active": true,
  "createdAt": "2026-10-01T08:00:00.000Z",
  "archivedAt": null
}
```

| Field | Type | Description |
| --- | --- | --- |
| `object` | string | The type of object. Always `discount_code`. |
| `livemode` | boolean | False for test-mode data (an `ak_test_` key); true for live data. |
| `id` | string | `dc_…` |
| `code` | string | What customers type, upper case. |
| `percentOffBps` | integer or null | Percent off in basis points (1500 is 15%). |
| `amountOffCents` | integer or null | Amount off. Integer cents. |
| `maxRedemptions` | integer or null | Most uses. |
| `redemptions` | integer | Uses so far. |
| `expiresAt` | string (date-time) or null | Expires. |
| `status` | string | `active`, `expired` (past `expiresAt`), `used_up` (reached `maxRedemptions`) or `archived` (deactivated). |
| `active` | boolean | Accepted at checkout now: not expired, not used up and not deactivated. |
| `createdAt` | string (date-time) | Created. |
| `archivedAt` | string (date-time) or null | Deactivated. |

## Endpoints

### Create a discount code

`POST /api/v1/discount-codes`

Permission: `discount_codes:write`. Supports `Idempotency-Key`.

A percentage or fixed amount off. Unique per business: 409 CODE_TAKEN otherwise. Codes made here apply to payment links that allow them. To use a code on subscription plans too, turn on **Use on subscriptions** for it in the dashboard (see [Subscription discounts](https://anytime-capital.com/docs/subscription-discounts.md)).

**Headers**

| Header | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | no | Recommended. A unique key such as a UUID: a retry with the same key within 24 hours gets the first response back instead of acting twice. See [Idempotency](https://anytime-capital.com/docs/idempotency.md). |

**Body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `code` | string | yes | 3–40 letters, numbers, dashes or underscores; stored upper case. |
| `percentOffBps` | integer or null | no | Percent off in basis points: 1500 is 15%. From 1 to 10,000. |
| `amountOffCents` | integer or null | no | Amount off, in cents. From 1 ($0.01) to 1,000,000 ($10,000.00). |
| `maxRedemptions` | integer or null | no | Most uses. From 1 to 1,000,000. |
| `expiresAt` | string (date-time) or null | no | When it stops working: in the future, within five years. |

**Request (curl)**

```bash
curl -X POST https://anytime-capital.com/api/v1/discount-codes \
  -H "Authorization: Bearer $ANYTIME_API_KEY" \
  -H "Idempotency-Key: discount-fall15" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "FALL15",
    "percentOffBps": 1500,
    "maxRedemptions": 100
  }'
```

**Request (Node.js)**

```javascript
const res = await fetch("https://anytime-capital.com/api/v1/discount-codes", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ANYTIME_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "discount-fall15",
  },
  body: JSON.stringify({ code: "FALL15", percentOffBps: 1500, maxRedemptions: 100 }),
});
const discountCode = await res.json();
if (!res.ok) throw new Error(`${discountCode.error.code}: ${discountCode.error.message}`);
```

**Request (Node SDK)**

```typescript
import { AnytimeCapital } from "@anytimecapital/node";

const client = new AnytimeCapital({ apiKey: process.env.ANYTIME_API_KEY! });

const discountCode = await client.discountCodes.create(
  { code: "FALL15", percentOffBps: 1500, maxRedemptions: 100 },
  { idempotencyKey: "discount-fall15" },
);
```

**Request (Python)**

```python
import os

import requests

res = requests.post(
    "https://anytime-capital.com/api/v1/discount-codes",
    headers={
        "Authorization": f"Bearer {os.environ['ANYTIME_API_KEY']}",
        "Idempotency-Key": "discount-fall15",
    },
    json={"code": "FALL15", "percentOffBps": 1500, "maxRedemptions": 100},
    timeout=30,
)
discountCode = res.json()
if not res.ok:
    raise RuntimeError(f"{discountCode['error']['code']}: {discountCode['error']['message']}")
```

**Response** (201)

```json
{
  "object": "discount_code",
  "livemode": true,
  "id": "dc_311",
  "code": "FALL15",
  "percentOffBps": 1500,
  "amountOffCents": null,
  "maxRedemptions": 100,
  "redemptions": 0,
  "expiresAt": null,
  "status": "active",
  "active": true,
  "createdAt": "2026-10-01T08:00:00.000Z",
  "archivedAt": null
}
```

**Errors**

| Status | Code | When |
| --- | --- | --- |
| 400 | `INVALID_JSON` | The body isn't valid JSON, or couldn't be read. An empty body reads as `{}`. Send `Content-Type: application/json` and a JSON object. |
| 400 | `INVALID_INPUT` | A field, filter, `limit` or `cursor` is missing or invalid. The message starts with the field's name, as in `amountCents: …`, or reads `Invalid cursor.` Fix the named field. Don't retry the same request unchanged. |
| 400 | `INVALID_IDEMPOTENCY_KEY` | The `Idempotency-Key` header is empty, longer than 255 characters, or has characters other than printable ASCII. Use a UUID. See [Idempotency](https://anytime-capital.com/docs/idempotency.md). |
| 409 | `CODE_TAKEN` | The business already has a discount code with this code. Pick another code, or use the existing one. |
| 422 | `IDEMPOTENCY_KEY_REUSED` | The `Idempotency-Key` was used in the last 24 hours with a different body or endpoint. Use a new key for a new request; reuse a key only to retry the same request. |

### List discount codes

`GET /api/v1/discount-codes`

Permission: `discount_codes:read`.

Discount codes, newest first.

**Query**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `active` | boolean | no | `true` for codes not deactivated (they may still have expired or run out: see `status`), `false` for deactivated ones. |
| `limit` | integer | no | How many objects per page, 1–100. Default 25. See [Pagination](https://anytime-capital.com/docs/pagination.md). |
| `cursor` | string | no | The previous page's `nextCursor`, for the page after it. |

**Request (curl)**

```bash
curl "https://anytime-capital.com/api/v1/discount-codes?active=true" \
  -H "Authorization: Bearer $ANYTIME_API_KEY"
```

**Request (Node.js)**

```javascript
const res = await fetch("https://anytime-capital.com/api/v1/discount-codes?active=true", {
  headers: { Authorization: `Bearer ${process.env.ANYTIME_API_KEY}` },
});
const page = await res.json();
if (!res.ok) throw new Error(`${page.error.code}: ${page.error.message}`);
```

**Request (Node SDK)**

```typescript
import { AnytimeCapital } from "@anytimecapital/node";

const client = new AnytimeCapital({ apiKey: process.env.ANYTIME_API_KEY! });

const page = await client.discountCodes.list({ active: true });
```

**Request (Python)**

```python
import os

import requests

res = requests.get(
    "https://anytime-capital.com/api/v1/discount-codes",
    headers={"Authorization": f"Bearer {os.environ['ANYTIME_API_KEY']}"},
    params={"active": "true"},
    timeout=30,
)
page = res.json()
if not res.ok:
    raise RuntimeError(f"{page['error']['code']}: {page['error']['message']}")
```

**Response** (200)

```json
{
  "object": "list",
  "data": [
    {
      "object": "discount_code",
      "livemode": true,
      "id": "dc_311",
      "code": "FALL15",
      "percentOffBps": 1500,
      "amountOffCents": null,
      "maxRedemptions": 100,
      "redemptions": 12,
      "expiresAt": "2026-11-30T23:59:59.000Z",
      "status": "active",
      "active": true,
      "createdAt": "2026-10-01T08:00:00.000Z",
      "archivedAt": null
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
```

**Errors**

| Status | Code | When |
| --- | --- | --- |
| 400 | `INVALID_INPUT` | A field, filter, `limit` or `cursor` is missing or invalid. The message starts with the field's name, as in `amountCents: …`, or reads `Invalid cursor.` Fix the named field. Don't retry the same request unchanged. |

### Get a discount code

`GET /api/v1/discount-codes/{id}`

Permission: `discount_codes:read`.

One discount code.

**Path**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | `dc_…` |

**Request (curl)**

```bash
curl https://anytime-capital.com/api/v1/discount-codes/dc_311 \
  -H "Authorization: Bearer $ANYTIME_API_KEY"
```

**Request (Node.js)**

```javascript
const res = await fetch("https://anytime-capital.com/api/v1/discount-codes/dc_311", {
  headers: { Authorization: `Bearer ${process.env.ANYTIME_API_KEY}` },
});
const discountCode = await res.json();
if (!res.ok) throw new Error(`${discountCode.error.code}: ${discountCode.error.message}`);
```

**Request (Node SDK)**

```typescript
import { AnytimeCapital } from "@anytimecapital/node";

const client = new AnytimeCapital({ apiKey: process.env.ANYTIME_API_KEY! });

const discountCode = await client.discountCodes.retrieve("dc_311");
```

**Request (Python)**

```python
import os

import requests

res = requests.get(
    "https://anytime-capital.com/api/v1/discount-codes/dc_311",
    headers={"Authorization": f"Bearer {os.environ['ANYTIME_API_KEY']}"},
    timeout=30,
)
discountCode = res.json()
if not res.ok:
    raise RuntimeError(f"{discountCode['error']['code']}: {discountCode['error']['message']}")
```

**Response** (200)

```json
{
  "object": "discount_code",
  "livemode": true,
  "id": "dc_311",
  "code": "FALL15",
  "percentOffBps": 1500,
  "amountOffCents": null,
  "maxRedemptions": 100,
  "redemptions": 12,
  "expiresAt": "2026-11-30T23:59:59.000Z",
  "status": "active",
  "active": true,
  "createdAt": "2026-10-01T08:00:00.000Z",
  "archivedAt": null
}
```

**Errors**

| Status | Code | When |
| --- | --- | --- |
| 404 | `NOT_FOUND` | No such object on your business (an id from another business reads the same), or no such endpoint under `/api/v1`, which still answers in JSON. Check the id and the path. Ids are case-sensitive. |

### Deactivate a discount code

`POST /api/v1/discount-codes/{id}/deactivate`

Permission: `discount_codes:write`. Supports `Idempotency-Key`.

Stop it being accepted at checkout. Safe to repeat. Payments that used it keep it; bring it back from **Discounts** in the dashboard.

**Path**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | `dc_…` |

**Headers**

| Header | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | no | Recommended. A unique key such as a UUID: a retry with the same key within 24 hours gets the first response back instead of acting twice. See [Idempotency](https://anytime-capital.com/docs/idempotency.md). |

**Request (curl)**

```bash
curl -X POST https://anytime-capital.com/api/v1/discount-codes/dc_311/deactivate \
  -H "Authorization: Bearer $ANYTIME_API_KEY" \
  -H "Idempotency-Key: discount-fall15-off"
```

**Request (Node.js)**

```javascript
const res = await fetch("https://anytime-capital.com/api/v1/discount-codes/dc_311/deactivate", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ANYTIME_API_KEY}`,
    "Idempotency-Key": "discount-fall15-off",
  },
});
const discountCode = await res.json();
if (!res.ok) throw new Error(`${discountCode.error.code}: ${discountCode.error.message}`);
```

**Request (Node SDK)**

```typescript
import { AnytimeCapital } from "@anytimecapital/node";

const client = new AnytimeCapital({ apiKey: process.env.ANYTIME_API_KEY! });

const discountCode = await client.discountCodes.deactivate(
  "dc_311",
  { idempotencyKey: "discount-fall15-off" },
);
```

**Request (Python)**

```python
import os

import requests

res = requests.post(
    "https://anytime-capital.com/api/v1/discount-codes/dc_311/deactivate",
    headers={
        "Authorization": f"Bearer {os.environ['ANYTIME_API_KEY']}",
        "Idempotency-Key": "discount-fall15-off",
    },
    timeout=30,
)
discountCode = res.json()
if not res.ok:
    raise RuntimeError(f"{discountCode['error']['code']}: {discountCode['error']['message']}")
```

**Response** (200)

```json
{
  "object": "discount_code",
  "livemode": true,
  "id": "dc_311",
  "code": "FALL15",
  "percentOffBps": 1500,
  "amountOffCents": null,
  "maxRedemptions": 100,
  "redemptions": 12,
  "expiresAt": "2026-11-30T23:59:59.000Z",
  "status": "archived",
  "active": false,
  "createdAt": "2026-10-01T08:00:00.000Z",
  "archivedAt": "2026-10-24T12:00:00.000Z"
}
```

**Errors**

| Status | Code | When |
| --- | --- | --- |
| 400 | `INVALID_IDEMPOTENCY_KEY` | The `Idempotency-Key` header is empty, longer than 255 characters, or has characters other than printable ASCII. Use a UUID. See [Idempotency](https://anytime-capital.com/docs/idempotency.md). |
| 404 | `NOT_FOUND` | No such object on your business (an id from another business reads the same), or no such endpoint under `/api/v1`, which still answers in JSON. Check the id and the path. Ids are case-sensitive. |
| 422 | `IDEMPOTENCY_KEY_REUSED` | The `Idempotency-Key` was used in the last 24 hours with a different body or endpoint. Use a new key for a new request; reuse a key only to retry the same request. |

---

Anytime Capital is a fintech company, not a bank. Payment processing, banking and payout services are provided by Anytime Capital's licensed partners. Rates shown are for US card payments; international cards, currency conversion and disputes may carry additional fees shown in your dashboard before you accept a payment.
