Skip to content
Docs

Create coupons and manage their pools of unique codes for emails.

Base URLhttps://api.emailit.com/v2AuthenticationErrorsRate limits

Create a coupon

Create a coupon. Put it in an email with {{coupon "key"}}: when the email is rendered, each recipient gets a code. Requires an API key with the full scope.

  • A unique coupon holds a pool of single-use codes. Each recipient is assigned the oldest free code, one per campaign or automation, and gets the same code again whenever that email is rendered for them. Upload your shop’s codes here or with Add coupon codes, or generate codes in Emailit and import them into your shop.
  • A static coupon has one code, static_code, for everyone.

When an order lists a code in coupon_codes, the code is marked redeemed. See Products, coupons and the cart.

POST/coupons

Request Body

keystringRequired

The name you use in content, unique in the workspace. 1 to 64 lowercase letters, digits, - or _, starting with a letter or digit. Uppercase letters are lowercased.

namestringRequired

Coupon name shown in the dashboard, up to 191 characters.

descriptionstring | null

Note for your team. Longer text is cut to 1,000 characters.

kindstring

unique (default) or static.

static_codestring | null

Up to 191 characters. Required for a static coupon: the code everyone gets. For a unique coupon, the text recipients get when the pool is empty or the coupon has expired. Without it, they get an empty string.

discount_labelstring | null

Short description of the discount, such as 10% off. Longer text is cut to 191 characters.

expires_atstring | null

ISO 8601 date-time. After it, recipients of a unique coupon get static_code instead of a code, also in emails rendered again. Emailit doesn’t enforce the expiry in your shop.

codesstring[] | string

Codes to add to the pool: an array, or text with one code per line. For CSV text, the first column is read and a header such as code or coupon_code is skipped. A code is 2 to 64 letters, digits, -, _ or ., starting with a letter or digit. Invalid codes are left out and duplicates are added once. Up to 10,000 codes.

Returns

201 Created with the coupon object. Returns 422 when a field is invalid or another coupon already has the key.

POST/coupons
Terminal
curl -X POST https://api.emailit.com/v2/coupons \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "welcome-10",
    "name": "Welcome 10% off",
    "description": "First-order discount for new subscribers.",
    "kind": "unique",
    "static_code": "WELCOME10",
    "discount_label": "10% off",
    "expires_at": "2026-12-31T23:59:59Z",
    "codes": ["WELCOME-7KQ2M9XA", "WELCOME-H4TZ8RCN", "WELCOME-P2WD6YFE"]
  }'
JSON
{
  "object": "coupon",
  "id": "cpn_3sMKUvFbx63T9hhDoNea7fmo1fQ",
  "key": "welcome-10",
  "name": "Welcome 10% off",
  "description": "First-order discount for new subscribers.",
  "kind": "unique",
  "static_code": "WELCOME10",
  "discount_label": "10% off",
  "expires_at": "2026-12-31T23:59:59.000Z",
  "codes_total": 3,
  "codes_available": 3,
  "codes_assigned": 0,
  "codes_redeemed": 0,
  "created_at": "2026-10-01T09:00:12.304Z",
  "updated_at": "2026-10-01T09:00:12.304Z"
}

Retrieve a coupon

Retrieve a coupon by its ID or its key, with counts of its codes. Requires an API key with the full scope.

GET/coupons/{id}

Path Parameters

idstringRequired

The coupon ID (cpn_...) or the coupon’s key.

The coupon object

objectstring

Always coupon.

idstring

Coupon ID (cpn_...).

keystring

The name you use in email content: {{coupon "welcome-10"}}. See Products, coupons and the cart.

namestring

Coupon name shown in the dashboard.

descriptionstring | null

Note for your team.

kindstring
  • unique: a pool of single-use codes. Each recipient gets their own code, one per campaign or automation, and the same code again when the email is rendered again.

  • static: one code, static_code, for everyone.

static_codestring | null

The shared code of a static coupon. For a unique coupon, the text recipients get when no code is left or the coupon has expired. Without it, they get an empty string.

discount_labelstring | null

Short description of the discount, such as 10% off.

expires_atstring | null

After this time, recipients of a unique coupon get static_code instead of a code.

codes_totalinteger

Codes in the pool.

codes_availableinteger

Codes that can still be handed out: not assigned to a contact and not used in an order.

codes_assignedinteger

Codes assigned to a contact, including the ones already redeemed.

codes_redeemedinteger

Codes used in an order (coupon_codes).

created_at, updated_atstring

When the coupon was created and last changed, in ISO 8601 UTC.

GET/coupons/{id}
Terminal
curl https://api.emailit.com/v2/coupons/welcome-10 \
  -H "Authorization: Bearer your_api_key"
JSON
{
  "object": "coupon",
  "id": "cpn_3sMKUvFbx63T9hhDoNea7fmo1fQ",
  "key": "welcome-10",
  "name": "Welcome 10% off",
  "description": "First-order discount for new subscribers.",
  "kind": "unique",
  "static_code": "WELCOME10",
  "discount_label": "10% off",
  "expires_at": "2026-12-31T23:59:59.000Z",
  "codes_total": 5000,
  "codes_available": 3812,
  "codes_assigned": 1188,
  "codes_redeemed": 143,
  "created_at": "2026-10-01T09:00:12.304Z",
  "updated_at": "2026-10-01T09:00:12.304Z"
}

Update a coupon

Update a coupon. Only the fields you send change. To add codes, use Add coupon codes: codes in this request is ignored. Requires an API key with the full scope.

If you change the key, update the {{coupon "key"}} tags in your emails too: Emailit looks coupons up by the key in the content.

POST/coupons/{id}

Path Parameters

idstringRequired

The coupon ID (cpn_...) or the coupon’s current key.

Request Body

Any of key, name, description, kind, static_code, discount_label and expires_at, with the rules of Create a coupon. Send null for description, static_code, discount_label or expires_at to clear it. A coupon that is or becomes static must keep a static_code.

Returns

200 OK with the updated coupon object. Returns 404 if no coupon matches id and 422 when a field is invalid or the new key is taken.

POST/coupons/{id}
Terminal
curl -X POST https://api.emailit.com/v2/coupons/welcome-10 \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "expires_at": "2027-01-31T23:59:59Z" }'
JSON
{
  "object": "coupon",
  "id": "cpn_3sMKUvFbx63T9hhDoNea7fmo1fQ",
  "key": "welcome-10",
  "name": "Welcome 10% off",
  "description": "First-order discount for new subscribers.",
  "kind": "unique",
  "static_code": "WELCOME10",
  "discount_label": "10% off",
  "expires_at": "2027-01-31T23:59:59.000Z",
  "codes_total": 5000,
  "codes_available": 3812,
  "codes_assigned": 1188,
  "codes_redeemed": 143,
  "created_at": "2026-10-01T09:00:12.304Z",
  "updated_at": "2026-10-09T15:47:20.061Z"
}

List coupons

List the coupons in your workspace, newest first, with counts of their codes. Requires an API key with the full scope.

GET/coupons

Query Parameters

pageinteger

Page number for pagination (minimum: 1, default: 1).

limitinteger

Number of coupons to return (minimum: 1, maximum: 100, default: 25).

searchstring

Case-insensitive match on the coupon name or key.

matchstring

all (default) requires every filter. or matches any filter. See Filtering.

orderstring

Sort key for this list. See the sort keys below.

directionstring

asc or desc.

Filters and sort

List filters are one layer of key.condition=value query parameters. See Filtering for match, order, direction and the condition list per type.

Filter keys

KeyTypeConditionsNotes
keystringexact, not_exact, contains, not_contains, starts_with, ends_with, empty, not_empty
namestringexact, not_exact, contains, not_contains, starts_with, ends_with, empty, not_empty
kindenumexact, not_exactValues: unique, static
expires_atdateexact, before, after, empty, not_empty
created_atdateexact, before, after, empty, not_empty

Sort keys

Pass order as one of these keys and direction as asc or desc: key, name, kind, expires_at, created_at

Returns

A page of coupon objects in data, with total_records, next_page_url and previous_page_url. The page URLs carry only page and limit, so add your search and filters again when you follow them.

GET/coupons
Terminal
curl "https://api.emailit.com/v2/coupons?kind.exact=unique" \
  -H "Authorization: Bearer your_api_key"
JSON
{
  "data": [
    {
      "object": "coupon",
      "id": "cpn_3sMKUvFbx63T9hhDoNea7fmo1fQ",
      "key": "welcome-10",
      "name": "Welcome 10% off",
      "description": "First-order discount for new subscribers.",
      "kind": "unique",
      "static_code": "WELCOME10",
      "discount_label": "10% off",
      "expires_at": "2026-12-31T23:59:59.000Z",
      "codes_total": 5000,
      "codes_available": 3812,
      "codes_assigned": 1188,
      "codes_redeemed": 143,
      "created_at": "2026-10-01T09:00:12.304Z",
      "updated_at": "2026-10-01T09:00:12.304Z"
    }
  ],
  "total_records": 1,
  "next_page_url": null,
  "previous_page_url": null
}

Delete a coupon

Delete a coupon together with all of its codes, including assigned and redeemed ones. Orders keep the codes in their coupon_codes. Requires an API key with the full scope.

DELETE/coupons/{id}

Path Parameters

idstringRequired

The coupon ID (cpn_...) or the coupon’s key.

DELETE/coupons/{id}
Terminal
curl -X DELETE https://api.emailit.com/v2/coupons/cpn_3sMKUvFbx63T9hhDoNea7fmo1fQ \
  -H "Authorization: Bearer your_api_key"
JSON
{
  "object": "coupon",
  "id": "cpn_3sMKUvFbx63T9hhDoNea7fmo1fQ",
  "deleted": true
}

List coupon codes

List the codes of a coupon, oldest first: the order in which they’re handed out. Use format=csv to export them, for example to import generated codes into your shop. Requires an API key with the full scope.

GET/coupons/{id}/codes

Path Parameters

idstringRequired

The coupon ID (cpn_...) or the coupon’s key.

Query Parameters

pageinteger

Page number for pagination (minimum: 1, default: 1).

limitinteger

Number of codes to return (minimum: 1, maximum: 100, default: 50).

statusstring
  • available: not assigned to a contact and not used in an order, so it can still be handed out.

  • assigned: assigned to a contact and not redeemed.

  • redeemed: used in an order.

formatstring

json (default) or csv. CSV returns every code that matches status in one file, without paging, with the columns code, status, email, assigned_at and redeemed_at. key.condition filters and sorting don’t apply to the CSV.

matchstring

all (default) requires every filter. or matches any filter. See Filtering.

orderstring

Sort key for this list. See the sort keys below.

directionstring

asc or desc.

Filters and sort

List filters are one layer of key.condition=value query parameters. See Filtering for match, order, direction and the condition list per type.

Filter keys

KeyTypeConditionsNotes
codestringexact, not_exact, contains, not_contains, starts_with, ends_with, empty, not_empty
emailstringexact, not_exact, contains, not_contains, starts_with, ends_with, empty, not_empty
assigned_atdateexact, before, after, empty, not_empty
redeemed_atdateexact, before, after, empty, not_empty
created_atdateexact, before, after, empty, not_empty

Sort keys

Pass order as one of these keys and direction as asc or desc: code, email, assigned_at, redeemed_at, created_at

Returns

A page of coupon codes in data, with total_records, next_page_url and previous_page_url. Each code has:

objectstring

Always coupon_code.

idstring

Code ID (cpc_...).

codestring

The code.

contact_id, emailstring | null

The contact the code is assigned to, or null.

source_idstring | null

The campaign (cmp_...) or automation (aut_...) whose email got the code.

assigned_atstring | null

When the code was assigned.

redeemed_at, redeemed_order_idstring | null

When the code was redeemed and by which order (ord_...).

created_atstring

When the code was added to the pool.

GET/coupons/{id}/codes
Terminal
curl "https://api.emailit.com/v2/coupons/welcome-10/codes?status=assigned&limit=2" \
  -H "Authorization: Bearer your_api_key"
JSON
{
  "data": [
    {
      "object": "coupon_code",
      "id": "cpc_3s6oCjlRbLFujYObEAcuiZmGKqu",
      "code": "WELCOME-H4TZ8RCN",
      "contact_id": "con_3MjLVacsYA6keJucAbOs3o3XhyA",
      "email": "grace@example.com",
      "source_id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
      "assigned_at": "2026-10-08T09:00:41.773Z",
      "redeemed_at": null,
      "redeemed_order_id": null,
      "created_at": "2026-10-01T09:00:12.304Z"
    },
    {
      "object": "coupon_code",
      "id": "cpc_3u9TrZTopqOgaqT9FcZFareUFGj",
      "code": "WELCOME-P2WD6YFE",
      "contact_id": "con_3EwrXnu9OaQWlfI1AyPUUEoYjQs",
      "email": "ada@example.com",
      "source_id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
      "assigned_at": "2026-10-08T09:00:41.802Z",
      "redeemed_at": null,
      "redeemed_order_id": null,
      "created_at": "2026-10-01T09:00:12.304Z"
    }
  ],
  "total_records": 1045,
  "next_page_url": "/v2/coupons/cpn_3sMKUvFbx63T9hhDoNea7fmo1fQ/codes?page=2&limit=2",
  "previous_page_url": null
}

Add coupon codes

Add codes to the pool of a unique coupon. Either upload codes that exist in your shop with codes, or let Emailit create random codes with generate and then import them into your shop with List coupon codes (format=csv). Codes already in the pool are skipped. Static coupons have one code and return 422. Requires an API key with the full scope.

POST/coupons/{id}/codes

Path Parameters

idstringRequired

The coupon ID (cpn_...) or the coupon’s key.

Request Body

Send codes or generate. When you send both, generate is used.

codesstring[] | string

Up to 10,000 codes: an array, or text with one code per line. For CSV text, the first column is read and a header such as code or coupon_code is skipped. A code is 2 to 64 letters, digits, -, _ or ., starting with a letter or digit. Codes that don’t match are returned in invalid.

generateobject

Create random codes from uppercase letters and digits, without 0, O, 1 and I, which are easy to mix up.

  • count (integer, required): 1 to 10,000 codes.

  • prefix (string): up to 20 letters, digits, - or _, put in front of every code. For example WELCOME-.

  • length (integer): random characters after the prefix, from 4 to 32. Defaults to 8. Values outside the range are clamped.

Returns

addedinteger

Codes added to the pool.

skippedinteger

Codes that were already in the pool.

invalidstring[]

Uploaded values that aren’t valid codes and weren’t added.

couponobject

The coupon object with the new counts.

Returns 404 if no coupon matches id, and 422 for a static coupon, when no valid code was sent, when more than 10,000 codes were sent, or when generate.count or generate.prefix is out of range.

POST/coupons/{id}/codes
Terminal
curl -X POST https://api.emailit.com/v2/coupons/welcome-10/codes \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "generate": { "count": 5000, "prefix": "WELCOME-", "length": 8 } }'
JSON
{
  "added": 5000,
  "skipped": 0,
  "invalid": [],
  "coupon": {
    "object": "coupon",
    "id": "cpn_3sMKUvFbx63T9hhDoNea7fmo1fQ",
    "key": "welcome-10",
    "name": "Welcome 10% off",
    "description": "First-order discount for new subscribers.",
    "kind": "unique",
    "static_code": "WELCOME10",
    "discount_label": "10% off",
    "expires_at": "2026-12-31T23:59:59.000Z",
    "codes_total": 5003,
    "codes_available": 5003,
    "codes_assigned": 0,
    "codes_redeemed": 0,
    "created_at": "2026-10-01T09:00:12.304Z",
    "updated_at": "2026-10-01T09:00:12.304Z"
  }
}

Was this page helpful?

Thanks for the feedback.

Thanks, we read every message.