CommetCommet
GitHubDiscordStatus
Introduction

Quickstart

Create an API KeyQuickstart

Learn

OffersIntroductory OffersPromotional OffersCard PromotionsPromo CodesMarkets and Regional PricingTrial Periods

Resources

SDK ReferenceAPI VersioningError HandlingTestingCLIExamples

Plugins

Better Auth
DocumentationKnowledge BaseBuild with AIAPI ReferenceWebhooks

Promotional Offers

Apply any compatible Offer directly for campaigns, retention, and experiments.

A Promotional Offer is an Offer applied directly with offerId. Promotional describes the application channel, not a different catalog resource or purpose.

The Offer stays independent from plans and prices until your integration selects it.

Create the terms

Direct Offers may combine a free trial with ordered discount or fixed-price phases:

const retentionOffer = await commet.offers.create({
  name: 'Return to Pro',
  phases: [
    { type: 'free_trial', durationDays: 7 },
    { type: 'fixed_price', durationCycles: 2, prices: [
      { currency: 'usd', amount: 2900 },
      { currency: 'ars', amount: 3990000 },
    ] },
    { type: 'percentage', durationCycles: null, percentage: 2000 },
  ],
})

Currency-specific phases require an explicit value for the checkout currency. Commet does not reuse a USD amount silently in another currency.

Apply it directly

await commet.subscriptions.create({
  customerId: 'user_123',
  planCode: 'pro',
  offerId: retentionOffer.id,
})

The Offer must be active, inside its availability window, and resolvable in the selected currency. It does not need a prior association with the plan or price.

An explicit offerId overrides automatic introductory selection. It cannot be combined with promoCode, customTrialDays, or skipTrial: true.

Immediate plan changes, plan-change previews, and supported reactivation flows also accept offerId. Scheduled plan changes do not accept an Offer.

Apply it to an active subscription

For retention, apply an Offer to a subscription that is already active. The discount phases start at the next billing cycle, so the current period stays untouched and the next invoice carries the discount:

await commet.subscriptions.applyOffer({
  id: 'sub_123',
  offerId: retentionOffer.id,
})

Only one Offer applies at a time: while an accepted Offer still has active or upcoming discount phases, a new application is rejected. Once its phases are exhausted, the subscription accepts a new Offer. Offers with a free trial phase cannot be applied to an active subscription, and the discount applies to the plan base price only.

The applied Offer belongs to that subscription and plan: it ends with a cancellation and a plan change removes it.

The same operation on a subscription with a pending payment checkout quotes or replaces the checkout discount instead; there it accepts an optional expiresAt for the quote.

Direct application or Promo Code?

Use direct offerId when your application decides who receives the terms. Use a Promo Code when the customer should enter a code and the campaign needs redemption restrictions.

A Promo Code can reference only an Offer with one percentage or amount_off phase. Multi-phase, trial, and fixed_price Offers remain available for direct application.

Related

  • Offers
  • Introductory Offers
  • Promo Codes
  • Manage Subscriptions

How is this guide?

Introductory Offers

Apply an existing Offer automatically to eligible new subscriptions.

Card Promotions

Distribute a Promotional Offer to eligible card BINs and revalidate eligibility at checkout.

On this page

Create the terms
Apply it directly
Apply it to an active subscription
Direct application or Promo Code?
Related