Discount

Create Discount

Changed on

Create a discount in a workspace. A code-type discount (the default) needs a unique code; a percentage discount needs percent; a fixed discount needs a positive amount.

Creating a discount publishes the code; it does not attach it to anything. The link between an order and a discount is a separate applied-discount record, written when a buyer redeems the code at checkout or when a ClickFunnels user applies it in the admin UI - which is why POST /api/v2/workspaces/{workspace_id}/orders takes no discount field and the discount_ids on an order are read-only. Writing applied discounts is not part of this API yet, and when it lands it will be that record you create rather than a discount field on the order. Until then an integration creates, reads, updates, expires and deletes discounts, and reads back which orders ended up carrying them.

post/workspaces/{workspace_id}/discounts

Request

Path parameters

workspace_idstring required

Request body

Example request

{
  "discount": {
    "name": "Launch 20",
    "code": "LAUNCH20",
    "discount_type": "code",
    "discount_method": "percentage",
    "percent": "20.0",
    "applies_to": "all_products"
  }
}

Response

Created

idinteger

Discount ID

public_idstring nullable

Discount public ID

workspace_idinteger

Workspace ID

namestring

Internal name for the discount.

codestring

The code a buyer redeems at checkout. Uppercased on save; unique within the workspace (cannot collide with a coupon code).

discount_type'code' | 'automatic' | 'sale'

code (the default) is a redeemable coupon code. automatic and sale are deprecated.

discount_method'percentage' | 'fixed' | 'shipping' | 'bogo'

How the discount is calculated. percentage uses percent; fixed uses amount. shipping and bogo exist but are outside the simple flow.

amountstring nullable

Fixed amount off, as a decimal string (e.g. "10.00"). null for a percentage discount.

percentstring nullable

Percentage off between 0.01 and 100 (e.g. "20.0"). null for a fixed discount.

currencystring

ISO currency code, lowercased. Defaults to the workspace currency.

applies_to'all_products' | 'specific_products' | 'specific_variants' | 'specific_collections'

Scope of the discount. all_products (the default) applies workspace-wide; the specific_* values restrict it to the ids passed in product_ids / variant_ids / products_collection_ids.

apply_fromstring date-time

When the discount becomes active. Defaults to the creation time.

apply_untilstring date-time nullable

When the discount expires. null means it never expires.

limit_1_per_customerboolean

When true, each contact can redeem the discount only once.

require_minimum_spendboolean

When true, the order must meet require_minimum_spend_amount for the discount to apply.

require_minimum_spend_amountinteger nullable

Minimum order subtotal required, when require_minimum_spend is true. In whole currency units, not cents - 50 on a usd discount means $50.

discounts_per_redemptioninteger nullable

Optional cap on how many line items a single redemption discounts.

redemptions_countinteger

How many times the discount has been redeemed on an invoice. On Stripe every invoice counts, renewals included; on Payments AI each customer redemption counts once, however many renewal invoices it covers. This is not a deletability signal - a discount can report zero redemptions and still return 422 on DELETE because it is applied to an order that has no invoice yet.

product_idsinteger[]

The products the discount is scoped to (empty unless applies_to is specific_products).

variant_idsinteger[]

The variants the discount is scoped to (empty unless applies_to is specific_variants).

products_collection_idsinteger[]

The collections the discount is scoped to (empty unless applies_to is specific_collections).

activeboolean

Derived - true when the discount is neither scheduled for the future nor expired.

expiredboolean

Derived - true when apply_until is in the past. An expired discount is frozen - every further update returns 422, so rename before you expire.

scheduledboolean

Derived - true when apply_from is in the future.

created_atstring date-time nullable

Added

updated_atstring date-time nullable

Updated

Example response

{
  "id": 771,
  "public_id": "gBEDMo",
  "workspace_id": 42000,
  "name": "Launch 20",
  "code": "LAUNCH20",
  "discount_type": "code",
  "discount_method": "percentage",
  "amount": null,
  "percent": "20.0",
  "currency": "usd",
  "applies_to": "all_products",
  "apply_from": "2025-01-01T00:00:00.000Z",
  "apply_until": null,
  "limit_1_per_customer": false,
  "require_minimum_spend": false,
  "require_minimum_spend_amount": null,
  "discounts_per_redemption": null,
  "redemptions_count": 0,
  "product_ids": [],
  "variant_ids": [],
  "products_collection_ids": [],
  "active": true,
  "expired": false,
  "scheduled": false,
  "created_at": "2025-01-01T00:00:00.000Z",
  "updated_at": "2025-01-01T00:00:00.000Z"
}

Changes