Products

Create Product

Creates a new product for an account.

post/products

Headers

Idempotency-Keystring
Example:d9105228-4a08-46b1-8b91-42fed586d383

A unique key that makes this request safe to retry. See Idempotent requests.

Request body

account_idstring

The unique identifier of the account to create this product for.

collect_shipping_addressboolean nullable

Whether to collect a shipping address at checkout.

custom_cta'get_access' | 'join' | 'order_now' | 'shop_now' | 'call_now' | 'donate_now' | 'contact_us' | 'sign_up' | 'subscribe' | 'purchase' | 'get_offer' | 'apply_now' | 'complete_order' | 'null' nullable

The call-to-action button label.

custom_cta_urlstring nullable

A URL the call-to-action button links to.

custom_statement_descriptorstring nullable

Custom bank statement descriptor. Must start with WHOP*.

descriptionstring nullable

A written description displayed on the product page. Maximum 1,500 characters.

global_affiliate_percentagenumber nullable

The commission rate affiliates earn.

global_affiliate_status'enabled' | 'disabled'

The enrollment status in the global affiliate program.

headlinestring nullable

A short marketing headline for the product page. Maximum 80 characters.

labelsstring[] nullable

Labels used to group products into collections. Stored lowercased and de-duplicated. Maximum 20 labels, 50 characters each.

member_affiliate_percentagenumber nullable

The commission rate members earn.

member_affiliate_status'enabled' | 'disabled'

The enrollment status in the member affiliate program.

metadataobject nullable

Custom key-value pairs to store on the product.

product_tax_code_idstring nullable

The unique identifier of the tax classification code. See the available product categories.

redirect_purchase_urlstring nullable

A URL to redirect the customer to after purchase.

routestring nullable

The URL slug for the product's public link.

send_welcome_messageboolean nullable

Whether to send an automated welcome message via support chat when a user joins this product. Defaults to true.

titlestring required

The display name of the product. Maximum 80 characters.

visibilitystring

Whether the product is visible to customers.

Example request

{
  "account_id": "biz_xxxxxxxxxxxxxx",
  "custom_cta": "order_now",
  "custom_cta_url": "https://shinetime.example/book",
  "custom_statement_descriptor": "WHOP*SHINETIME",
  "description": "Full interior extraction, leather conditioning, and an ozone odor treatment.",
  "gallery_images": [
    {
      "direct_upload_id": "eyJfcmFpbHMiOnsiZGF0YSI6MSwicHVyIjoiYmxvYl9pZCJ9fQ==--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "id": "file_xxxxxxxxxxxxxx"
    }
  ],
  "global_affiliate_percentage": 10,
  "global_affiliate_status": "enabled",
  "headline": "Steam, shampoo, and odor removal in one visit",
  "labels": [
    "interior"
  ],
  "member_affiliate_percentage": 5,
  "member_affiliate_status": "enabled",
  "metadata": {
    "bay": "1",
    "duration_hours": "4"
  },
  "product_tax_code_id": "ptc_xxxxxxxxxxxxxx",
  "redirect_purchase_url": "https://shinetime.example/thanks",
  "route": "interior-deep-clean",
  "send_welcome_message": true,
  "title": "Interior Deep Clean",
  "visibility": "visible"
}

Response

product created

accountobject nullable required

Account that sells this product.

average_review_ratingnumber required

Average star rating across published reviews for this product, from 1.0 to 5.0. Returns 0.0 when no published-review rating is available.

created_atstring required

When the product was created, as an ISO 8601 timestamp.

custom_cta'get_access' | 'join' | 'order_now' | 'shop_now' | 'call_now' | 'donate_now' | 'contact_us' | 'sign_up' | 'subscribe' | 'purchase' | 'get_offer' | 'apply_now' | 'complete_order' | 'null' nullable required

Call-to-action button label shown on the product purchase page.

custom_cta_urlstring nullable required

URL the call-to-action button links to instead of checkout.

custom_statement_descriptorstring nullable required

Custom text label on customer's bank statement.

descriptionstring nullable required

Written description displayed on the product page. null if none is set.

external_identifierstring nullable required

External identifier stored on the product for your own reference.

global_affiliate_percentagenumber nullable required

Commission rate affiliates earn through the global affiliate program.

global_affiliate_status'enabled' | 'disabled' | 'null' nullable required

Enrollment status in the global affiliate program.

headlinestring nullable required

Short marketing headline displayed on product page.

idstring required

Product ID, prefixed prod_.

labelsstring[] required
marketplace_status'not_available' | 'pending_review' | 'live_marketplace' required

Listing state on the whop.com marketplace. pending_review means submitted and awaiting review; live_marketplace means approved and discoverable.

member_affiliate_percentagenumber nullable required

Commission rate members earn through the member affiliate program.

member_affiliate_status'enabled' | 'disabled' | 'null' nullable required

Enrollment status in the member affiliate program.

member_countnumber required

Active memberships for this product; 0 if public member counts are disabled.

metadataobject nullable required

Custom key-value pairs stored on the product.

owner_userobject nullable required

User who owns the account selling this product.

product_tax_codeobject nullable required

Tax classification code for this product, or null if no tax code is set.

published_reviews_countnumber required

Published customer reviews for this product.

routestring required

URL slug for the product's public link.

titlestring required

Product display name shown to customers.

updated_atstring required

When the product was last updated, as an ISO 8601 timestamp.

variant_attributesobject nullable required

The option set the product's variants span, as a map of attribute name to the values in use, e.g. {"color": ["Blue", "Red"], "size": ["S", "M", "L"]}. Derived from the visible, non-invoice plans that carry attributes: keys alphabetical, values in the order the plans were created. Read-only. null when the product has no variants.

verifiedboolean required

Whether the product has been verified by Whop.

visibilitystring nullable required

Whether the product is publicly visible, hidden, or archived.

Example response

{
  "account": {
    "id": "biz_xxxxxxxxxxxxxx",
    "route": "biz_xxxxxxxxxxxxxx",
    "title": "Shine Time Auto Detailing"
  },
  "created_at": "2026-01-01T12:00:00.000Z",
  "custom_cta": "order_now",
  "custom_cta_url": "https://shinetime.example/book",
  "custom_statement_descriptor": "WHOP*SHINETIME",
  "default_plan": {
    "billing_period": 30,
    "id": "plan_xxxxxxxxxxxxxx",
    "initial_price": {
      "amount": "-2.50",
      "currency": "usd",
      "decimals": 2,
      "display_decimals": 2
    },
    "plan_type": "renewal",
    "renewal_price": {
      "amount": "-2.50",
      "currency": "usd",
      "decimals": 2,
      "display_decimals": 2
    },
    "unlimited_stock": true,
    "visibility": "visible"
  },
  "description": "Full interior extraction, leather conditioning, and an ozone odor treatment.",
  "external_identifier": "SHINE-CERAMIC-01",
  "gallery_images": [
    {
      "content_type": "image/png",
      "id": "file_xxxxxxxxxxxxxx",
      "url": "https://whop-assets-example.s3.amazonaws.com/uploads/image/2026-01-01/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    }
  ],
  "global_affiliate_percentage": 10,
  "global_affiliate_status": "enabled",
  "headline": "Steam, shampoo, and odor removal in one visit",
  "id": "prod_xxxxxxxxxxxxxx",
  "labels": [
    "interior"
  ],
  "marketplace_status": "not_available",
  "member_affiliate_percentage": 5,
  "member_affiliate_status": "enabled",
  "metadata": {
    "bay": "1",
    "duration_hours": "4"
  },
  "owner_user": {
    "id": "user_xxxxxxxxxxxxxx",
    "name": "Marcus Webb",
    "username": "marcuswebb"
  },
  "product_tax_code": {
    "id": "ptc_xxxxxxxxxxxxxx",
    "name": "General - Digital Goods",
    "product_type": "digital"
  },
  "route": "interior-deep-clean",
  "title": "Interior Deep Clean",
  "updated_at": "2026-01-01T12:00:00.000Z",
  "variant_attributes": {
    "color": [
      "Red",
      "Blue"
    ],
    "size": [
      "M",
      "S"
    ]
  },
  "variants": [
    {
      "account": {
        "id": "biz_xxxxxxxxxxxxxx",
        "title": "Shine Time Auto Detailing"
      },
      "adaptive_pricing_enabled": true,
      "attributes": {
        "color": "Blue",
        "size": "S"
      },
      "billing_period": 30,
      "cancel_discount_intervals": 3,
      "cancel_discount_percentage": 20,
      "checkout_styling": {
        "background_color": "#0f172a",
        "border_style": "rounded",
        "button_color": "#f59e0b",
        "font_family": "roboto"
      },
      "created_at": "2026-01-01T12:00:00.000Z",
      "currency": "usd",
      "custom_fields": [
        {
          "field_type": "text",
          "id": "field_xxxxxxxxxxxxxx",
          "name": "Vehicle make and model",
          "placeholder": "2021 Audi S5",
          "required": true
        }
      ],
      "description": "Two hand washes a month, interior vacuum, and a quarterly sealant top-up.",
      "expiration_days": 365,
      "formatted_price": "$59.00 / month",
      "id": "plan_xxxxxxxxxxxxxx",
      "image": {
        "blurhash": "LA6bDXT$E3b:R6i+RibEIWbp%ej1",
        "url": "https://whop-assets-example.s3.amazonaws.com/uploads/image/2026-01-01/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      },
      "initial_price_due": {
        "amount": "-2.50",
        "currency": "usd",
        "decimals": 2,
        "display_decimals": 2
      },
      "internal_notes": "Maintenance tier. Upsell the interior shampoo add-on at renewal.",
      "invoice": {
        "id": "inv_xxxxxxxxxxxxxx"
      },
      "metadata": {
        "custom_cta": "subscribe",
        "custom_cta_url": "https://shinetime.example/wash-club"
      },
      "offer_cancel_discount": true,
      "payment_method_configuration": {
        "disabled": [
          "crypto"
        ],
        "enabled": [
          "card"
        ],
        "include_platform_defaults": true
      },
      "plan_type": "renewal",
      "product": {
        "id": "prod_xxxxxxxxxxxxxx",
        "title": "Ceramic Coating Package"
      },
      "purchase_url": "https://whop.com/checkout/plan_xxxxxxxxxxxxxx",
      "release_method": "buy_now",
      "renewal_price": 59,
      "sku": "CERAMIC-COATING-S-BLUE",
      "split_pay_required_payments": 4,
      "strike_through_initial_price": 99,
      "strike_through_renewal_price": 79,
      "three_ds_level": "frictionless_if_required",
      "title": "Unlimited Wash Club",
      "trial_period_days": 7,
      "updated_at": "2026-01-01T12:00:00.000Z",
      "visibility": "visible"
    }
  ],
  "visibility": "visible"
}

Changes

Changed in 10 of the 74 revisions of this API.192455

  • 7fcefabddb0a32See the full diff
    • ●

      the request property's maxLength was set to 1500

      request-property-max-length-set

    • ●

      the request property's maxLength was set to 80

      request-property-max-length-set

    • ●

      the request property's maxLength was set to 80

      request-property-max-length-set

    • ○

      added the required property to the response with the status

      response-required-property-added

    • ○

      added the required property to the response with the status

      response-required-property-added

    This revision also has 1 change that name no endpoint, such as unreferenced schemas being removed. See the revision's changelog

    • ○

      added the new optional request property

      new-optional-request-property

    This revision also has 1 change that name no endpoint, such as unreferenced schemas being removed. See the revision's changelog

    • ○

      added the required property to the response with the status

      response-required-property-added

    This revision also has 1 change that name no endpoint, such as unreferenced schemas being removed. See the revision's changelog

    • ○

      added the required property to the response with the status

      response-required-property-added

    • ○

      added the new optional request property

      new-optional-request-property

    • ○

      added the required property to the response with the status

      response-required-property-added

    This revision also has 1 change that name no endpoint, such as unreferenced schemas being removed. See the revision's changelog

    • ○

      added the non-success response with the status

      response-non-success-status-added

    • ○

      added the optional property / to the response with the status

      response-optional-property-added

    This revision also has 9 changes that name no endpoint, such as unreferenced schemas being removed. See the revision's changelog

    • ○

      the security scope access_pass:create was added to the endpoint's security scheme bearerAuth

      api-security-scope-added

    • ○

      the security scope product:create was removed from the endpoint's security scheme bearerAuth

      api-security-scope-removed

    This revision also has 16 changes that name no endpoint, such as unreferenced schemas being removed. See the revision's changelog

  • 099fdc3be42232018See the full diff
    • ▲

      request property was restricted to a list of enum values

      request-property-became-enum

    • ▲

      request property was restricted to a list of enum values

      request-property-became-enum

    • ▲

      request property was restricted to a list of enum values

      request-property-became-enum

    • ●

      added the new apply_now enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new call_now enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new complete_order enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new contact_us enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new disabled enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new disabled enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new donate_now enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new enabled enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new enabled enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new get_access enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new get_offer enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new join enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new order_now enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new purchase enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new shop_now enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new sign_up enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new subscribe enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new undefined enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new undefined enum value to the response property for the response status

      response-property-enum-value-added

    • ●

      added the new undefined enum value to the response property for the response status

      response-property-enum-value-added

    • ○

      added the new apply_now enum value to the request property

      request-property-enum-value-added

    • ○

      added the new call_now enum value to the request property

      request-property-enum-value-added

    • ○

      added the new complete_order enum value to the request property

      request-property-enum-value-added

    • ○

      added the new contact_us enum value to the request property

      request-property-enum-value-added

    • ○

      added the new disabled enum value to the request property

      request-property-enum-value-added

    • ○

      added the new disabled enum value to the request property

      request-property-enum-value-added

    • ○

      added the new donate_now enum value to the request property

      request-property-enum-value-added

    • ○

      added the new enabled enum value to the request property

      request-property-enum-value-added

    • ○

      added the new enabled enum value to the request property

      request-property-enum-value-added

    • ○

      added the new get_access enum value to the request property

      request-property-enum-value-added

    • ○

      added the new get_offer enum value to the request property

      request-property-enum-value-added

    • ○

      added the new join enum value to the request property

      request-property-enum-value-added

    • ○

      added the new order_now enum value to the request property

      request-property-enum-value-added

    • ○

      added the new purchase enum value to the request property

      request-property-enum-value-added

    • ○

      added the new shop_now enum value to the request property

      request-property-enum-value-added

    • ○

      added the new sign_up enum value to the request property

      request-property-enum-value-added

    • ○

      added the new subscribe enum value to the request property

      request-property-enum-value-added

    • ○

      added the new undefined enum value to the request property

      request-property-enum-value-added

    This revision also has 4 changes that name no endpoint, such as unreferenced schemas being removed. See the revision's changelog

  • 60bbb4a6ffbc16126See the full diff
    • ▲

      the response property became nullable for the status

      response-property-became-nullable

    • ▲

      the response property became nullable for the status

      response-property-became-nullable

    • ▲

      the response property became nullable for the status

      response-property-became-nullable

    • ▲

      the response property became nullable for the status

      response-property-became-nullable

    • ▲

      the response property became nullable for the status

      response-property-became-nullable

    • ▲

      the response's property format changed from date-time to no format for status

      response-property-type-changed

    • ▲

      the response's property type changed from integer to number for status

      response-property-type-changed

    • ▲

      the response's property type changed from integer to number for status

      response-property-type-changed

    • ▲

      the response's property format changed from date-time to no format for status

      response-property-type-changed

    • ▲

      removed the required property from the response with the status

      response-required-property-removed

    • ▲

      removed the required property / from the response with the status

      response-required-property-removed

    • ▲

      removed the required property / from the response with the status

      response-required-property-removed

    • ▲

      removed the required property / from the response with the status

      response-required-property-removed

    • ▲

      removed the required property / from the response with the status

      response-required-property-removed

    • ▲

      removed the required property / from the response with the status

      response-required-property-removed

    • ▲

      removed the required property / from the response with the status

      response-required-property-removed

    • ●

      removed the request property

      request-property-removed

    • ○

      added the new optional header request parameter Idempotency-Key

      new-optional-request-parameter

    • ○

      added the new optional request property

      new-optional-request-property

    • ○

      removed the apply_now enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the archived enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the call_now enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the complete_order enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the contact_us enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the disabled enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the disabled enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the donate_now enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the enabled enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the enabled enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the get_access enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the get_offer enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the hidden enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the join enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the order_now enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the purchase enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the quick_link enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the shop_now enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the sign_up enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the subscribe enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      removed the visible enum value from the response property for the response status

      response-property-enum-value-removed

    • ○

      added the required property to the response with the status

      response-required-property-added

    • ○

      added the required property // to the response with the status

      response-required-property-added

    • ○

      added the required property to the response with the status

      response-required-property-added

    This revision also has 1 change that name no endpoint, such as unreferenced schemas being removed. See the revision's changelog

Of the 74 revisions, 1 has no diff computed.