Create promo code

POST /api/configuration/promotion-codes

Success: 201 Created

Overview

Creates a promo code — the short string a customer types at checkout to pull in one or more discounts you have already configured. The promo code itself carries no money off; it is a validity window plus a list of discount ids, and the discounts decide what is actually reduced. You therefore have to create the discounts first.

The identifier is chosen by the platform, not by you: it is an automatically allocated integer, and that integer is the entire body of the 201 Created response — a bare JSON number such as 12345, not an object. Keep it, because it is what Update promo code takes in its path. The Location header points back at this same collection URL rather than at the new promo code, so it is of no use to you. If you lose the id and only have the code string, Get promo code by ID or code will find it — but that endpoint treats a bare path segment as a numeric id, so the code has to be wrapped in curly braces: /api/configuration/promotion-codes/{SUMMER24}.

Retrying is safe in the ordinary case: code must be unique, compared case-insensitively, and a repeat returns 409 Conflict with a message that includes the id of the existing promo code — so you can recover the id from the error. Be aware, though, that uniqueness is not guaranteed under concurrency: two identical requests arriving at the same moment can both succeed and leave you with two promo codes sharing a code. Nothing else on the request is checked for uniqueness.

The remaining validation is about time and is stricter than it first looks. validFrom must be today or later and validTo must be strictly later than today, both compared as dates in UTC with the time of day discarded, so a code cannot be created that starts and finishes on the same day, and no code can be back-dated.

Endpoint

POST {base_url}/api/configuration/promotion-codes

{base_url} is the environment URL issued to your integration. See Authenticating with Gladstone APIs.

Request body

FieldTypeRequiredDescription
codestringYesThe string customers actually type, up to 25 characters. It must contain no whitespace anywhere — not even in the middle — and must not match an existing promo code, compared case-insensitively, so SUMMER24 clashes with summer24. It is stored exactly as you send it, but every lookup ignores case.
validFromstring (date-time)YesThe first day the code can be redeemed. Only the date part is kept; any time of day you send is discarded, so the code is live from the very start of that day. It must be today or later in UTC — back-dating is rejected — and must not be after validTo.
validTostring (date-time)YesThe expiry day. Only the date part is kept. It is exclusive where validFrom is inclusive: redemption fails as soon as the current UTC date reaches validTo, so set it to the day after the last day you want the code to work. It must be strictly later than today, which makes tomorrow the earliest value this endpoint accepts.
maxUsagesinteger (int32)YesHow many times the code may be redeemed in total. Must be 0 or greater. 0 means unlimited, and the retrieval endpoints report maxUsage as 0 for an unlimited code. The separate remaining-usages count starts at the number you send, so an unlimited code starts life reporting usagesRemaining of 0.
activebooleanYesWhether the code is currently enabled. This is enforced at redemption: membership pricing rejects an inactive code with Promotion code {code} is not currently active, regardless of its dates. It also controls visibility on Get all promo codes, which omits inactive codes unless you pass includeInactive=true. Send false to stage a campaign in advance and switch it on later with Update promo code.
autoApplybooleanYesStored against the promo code and returned by the retrieval endpoints. The field is mandatory — omitting it fails request validation — so send false unless you have been told otherwise.
discountIdsarray of integerYesThe discounts this code switches on, by id. At least one is required, and every id must already exist or the whole request fails with 400 listing the ids it could not find. The ids come from the response of Create a discount — which returns an array of ids, one per membership type, when the discount covers several — or from Get all discounts. The discounts are what determine the actual reduction and which membership types it applies to; a code whose discounts match none of the memberships being bought is rejected at pricing time, not here.

Sample request

cURL
curl -X POST '{base_url}/api/configuration/promotion-codes' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "code": "string",
  "validFrom": "2026-08-14T19:00:00Z",
  "validTo": "2026-08-14T19:00:00Z",
  "maxUsages": 1,
  "active": true,
  "autoApply": true,
  "discountIds": [
    12345
  ]
}'

Sample response

201 Created
1

Errors

Every failure below returns the message as a plain string body, except request validation, which returns a validation problem document (application/problem+json) with an errors map keyed by field name.

StatusMeaningWhen
400Bad requestRequest validation failed before any other check: code missing or longer than 25 characters, validFrom or validTo missing, maxUsages missing or negative, active or autoApply missing, or discountIds missing or empty. The messages are The field 'Code' is a mandatory field, The field 'Code' can not exceed 25 characters, ValidFrom date must be provided, ValidTo date must be provided, MaxUsages must be supplied, Max Usages must be 0 or greater, Active must be supplied, AutoApply must be supplied and At least one discount ID must be supplied.
400Bad requestMalformed JSON, or a value of the wrong type for its field.
400Bad requestcode contains a space, tab or other whitespace character. Body: Promo-code code can not have any blank spaces..
400Bad requestvalidTo is today or earlier in UTC. Body: The Valid To date must be a future date.
400Bad requestvalidFrom is before today in UTC. Body: The Valid From date must be from today onwards.
400Bad requestvalidTo is earlier than validFrom. Body: The Valid To date must be a future date and after the Valid From date.
400Bad requestOne or more entries in discountIds do not exist. Body: The following discount IDs do not exist and can not be mapped to a promo-code: {ids}, listing exactly which ids were not found. Nothing is created.
409ConflictA promo code with the same code already exists, ignoring case. Body: A promo-code with the code '{code}' already exists with an ID of {id} — the existing id is in the message, so you can carry on without a second call.
500Internal server errorAny unexpected server-side failure. The promo code and its discount links are saved in two separate steps, so a failure between them can leave a promo code with no discounts attached; check with Get promo code by ID or code before retrying.

This page as markdown · All pages · llms.txt