Skip to content

Create a promotion code

The promotion_codes.create operation: POST /api/v1/promotion_codes in the REST API and the promotion_codes_create tool in the MCP server.

POST/api/v1/promotion_codes

Creates a customer-facing code for a coupon, such as LAUNCH50. Customers enter it at checkout (any case); codes are unique in the brand and mode and are never reused, archived ones included.

restrictions limit who can use it and when: firstTimeOnly (no earlier successful payment or paid invoice), minimumAmount (the purchase before discounts, same currency), customerId, expiresAt and maxRedemptions. They are checked when the code is applied; redemptions are counted on successful payment. The code and its restrictions can't change later: archive it and create another.

At a glance

  • REST: POST /api/v1/promotion_codes
  • MCP tool: promotion_codes_create
  • Operation ID: promotion_codes.create
  • Scope: Brand
  • Permission: catalog:write
  • Risk tier: write
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: API key with the catalog:write scope
  • Since: M5

Request

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
couponIdcpn_… IDYesThe coupon customers get with the code.
codestringYesWhat customers type, e.g. LAUNCH50. Case doesn't matter; unique in the brand and mode.
restrictionsobjectNoWho can use the code and when. They can't change later: create a new code instead.
restrictions.firstTimeOnlybooleanNoOnly customers without an earlier successful payment or paid invoice.
restrictions.minimumAmountobjectNoThe purchase before discounts must reach this amount, in the same currency.
restrictions.minimumAmount.amountstringYesInteger micros as a string (12500000 = 12.50).
restrictions.minimumAmount.currencystringYesISO 4217 currency code: the price's currency.
restrictions.customerIdcus_… IDNoOnly this customer can use the code.
restrictions.expiresAtdate-timeNoThe code can't be used from this instant on.
restrictions.maxRedemptionsintegerNoHow many times it can be redeemed in total (counted on successful payment).
activebooleanNoDefault true; false creates it archived.
metadataobjectNoYour own key-value pairs (at most 50 keys). On updates the whole set is replaced.

Response

201 Created with a JSON object:

FieldTypeDescription
idpromo_… ID
object"promotion_code"
brandIdbrd_… ID
livemodeboolean
couponIdcpn_… ID
codestringAs entered; customers may type it in any case.
restrictionsobject
restrictions.firstTimeOnlyboolean
restrictions.minimumAmountmoney or null
restrictions.customerIdstring or null
restrictions.expiresAtdate-time or null
restrictions.maxRedemptionsinteger or null
timesRedeemedinteger
activeboolean
metadataobject
createdAtdate-time
updatedAtdate-time

Examples

A launch code for first-time customers

HTTP
POST /api/v1/promotion_codes
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "couponId": "cpn_01m4tx5nj8emwbyf7y9vcf47z0",
  "code": "LAUNCH50",
  "restrictions": {
    "firstTimeOnly": true,
    "maxRedemptions": 200
  }
}

Response (201):

JSON
{
  "id": "promo_01m4tx5nj8emwbyf7y9vcf47z2",
  "object": "promotion_code",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "couponId": "cpn_01m4tx5nj8emwbyf7y9vcf47z0",
  "code": "LAUNCH50",
  "restrictions": {
    "firstTimeOnly": true,
    "minimumAmount": null,
    "customerId": null,
    "expiresAt": null,
    "maxRedemptions": 200
  },
  "timesRedeemed": 0,
  "active": true,
  "metadata": {},
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T12:00:00.000Z"
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400The code or a restriction is malformed, or expiresAt is in the past.Fix the fields listed in details.issues and send the request again.
promotion_code_taken409The brand already has this code in this mode (in any case).Choose another code. Codes are compared without regard to case and are never reused.
coupon_not_redeemable409The coupon is archived, expired or used up.Check details.reason: reactivate an archived coupon, or create a new coupon when it expired or reached its redemption limit.
resource_not_found404The coupon or the restricted customer isn't in this brand and mode.Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
customer_deleted400The restricted customer was deleted.Create a new customer for this buyer. Deleted customers stay readable for the records they belong to, but can't be changed.
permission_denied403You can't change this brand's catalog.Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, scope_required, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.