Commet
  • Pricing
Log InTry out

Offers & Pricing

Create regional and selectable prices, apply phased Offers, compare packages with A/B tests, and migrate SDK and CLI integrations to v8.

D
Decker Urbano·@0xDecker·July 28, 2026
Changelog

Install the Commet v7 to v8 migration skill so your coding agent can update SDK calls, API pins, CLI commands, and webhook versions.

npx skills add commet-labs/skills --skill migrate-commet-v7-to-v8

If you only need to upgrade an existing integration, use the migration skill above. Read on to understand what changed and how the new pieces work together.

Pricing defines the amount and package a customer can buy. Offers define how that price changes over time. They stay separate in the catalog and come together when the customer subscribes.

Pricing

Start with one Pro plan. It can keep its standard monthly price, show a local price in Argentina, and offer a selectable launch package without duplicating the plan.

  • Currency Pricing sets a value for a currency.
  • Markets group countries that should see a specific price and currency.
  • Selectable variants represent packages a customer can deliberately choose while inheriting the base price everywhere else.

A Market is reusable across prices and does not require a plan when you create it:

const argentina = await commet.pricing.createMarketGroup({
  name: 'Argentina',
  countryCodes: ['AR'],
})

A selectable variant links back to its base through inheritsFromPriceId. Pass its public priceId when the customer chooses that package; omit it when Commet should resolve the normal price from the billing country.

The subscription remembers that choice. Future renewals use the current catalog value for the selected package. Once the price is selected, an Offer can change its terms over time without duplicating the pricing configuration.

Offers

Pricing answers “how much?” An Offer answers “how does that amount change over time?” It can add a trial, a discount for several billing cycles, or a fixed introductory price without creating another package.

PurposeSelectionPhases
introductoryAutomatic from one base plan priceOptional free trial, then percentage or amount off
promotionalExplicit offerId or a Promo CodePercentage, amount off, or fixed price across ordered phases
const launchOffer = await commet.offers.create({
  name: 'Launch pricing',
  purpose: 'promotional',
  planPriceIds: ['pp_pro_monthly'],
  phases: [
    { type: 'percentage', durationCycles: 2, percentage: 5000 },
    { type: 'percentage', durationCycles: 2, percentage: 2500 },
  ],
})

When a customer accepts an Offer, Commet saves those phases as their agreed terms. Editing or archiving the catalog Offer changes future applications, not the deal an existing customer already accepted.

Combine them at subscription creation

The subscription is where both decisions meet: the price selects the package and the Offer defines its promotional schedule. In the API, priceId and offerId make those choices explicit.

await commet.subscriptions.create({
  customerId: 'user_123',
  planCode: 'pro',
  priceId: 'pp_pro_launch',
  offerId: 'ofr_launch_2026',
})

Price variants inherit Offer eligibility from their base price. If you omit offerId, Commet keeps automatic Introductory Offer selection. An explicit Promotional offerId cannot be combined with promoCode, customTrialDays, or skipTrial: true.

That explicit combination also gives each experiment cohort one stable billing outcome.

A/B tests

For example, the control group can receive the standard monthly package while the variant receives a launch package with a Promotional Offer. Assign each customer to a stable cohort in your application or experimentation system, then pass the selected terms:

const selection =
  experimentVariant === 'control'
    ? { priceId: 'pp_pro_monthly' }
    : {
        priceId: 'pp_pro_launch',
        offerId: 'ofr_launch_2026',
      }

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

Commet bills and renews the selected terms. Your application still owns cohort assignment and conversion measurement.

All v8 changes

Pricing, Offers, and their explicit composition shipped with API version 2026-07-24, SDK v8, and CLI v4. The same release aligns the rest of the public contract around direct resource results, exact request alternatives, and the current usage API.

Existing integrations keep working until you upgrade the SDK, change an explicit commet-version header, update an organization pin, or repin a webhook endpoint.

v7v8
Singular results used SDK response wrappersSingular operations return the resource directly
featureAccess.canUse(...)usage.check(...)
usage.trackEvent(...)usage.track(...)
Raw usage field featurefeatureCode
SDK-generated event identifierOptional caller-owned eventId
Inline introductory and promo discount fieldsFirst-class Offers and Promo Codes that reference Promotional Offers
Default plan price onlyOptional selectable priceId, reusable Markets, and inherited price variants
Broad request and response shapesExact discriminated unions from the API contract
feature-access can-use and usage track --feature in the CLIusage check and usage track --feature-code

List methods still return { object, data, hasMore, nextCursor }. Authentication, request idempotency, webhook signature verification, and framework helpers remain ergonomic SDK capabilities.

Upgrade the SDK

# Node.js
npm install @commet/node@^8

# Python
pip install "commet-sdk>=8,<9"

# Go
go get github.com/commet-labs/commet-go/v8

# PHP
composer require commet/commet-php:^8.0

# Java
# co.commet:commet-java:8.0.0

Remove singular response wrappers

// v7
const { data: customer } = await commet.customers.create({
  id: 'user_123',
  email: 'user@example.com',
})

// v8
const customer = await commet.customers.create({
  id: 'user_123',
  email: 'user@example.com',
})

Keep data for list operations:

const { data: customers, hasMore, nextCursor } = await commet.customers.list()

Update usage

const availability = await commet.usage.check({
  customerId: 'user_123',
  featureCode: 'api_calls',
})

const event = await commet.usage.track({
  customerId: 'user_123',
  featureCode: 'api_calls',
  value: 1,
  eventId: 'request_01JXYZ',
})

eventId identifies the business event and makes retries safe. Transport idempotency remains a request option and maps to the Idempotency-Key header.

Upgrade the CLI

CLI v4 adds Offers, pricing Market Groups, selectable price variants, Offer-aware subscription flows, and the current usage commands.

npm install -g commet@^4

commet offers list
commet pricing list-market-groups
commet usage check --customer-id customer_123 --feature-code api_calls

Use --feature-code instead of --feature when tracking usage, and pass the caller-owned event identifier with --event-id. usage check replaces feature-access can-use. Promo Code commands now reference a Promotional Offer with --offer-id.

Use exact request alternatives

SDK v8 models mutually exclusive request shapes as discriminated unions:

  • Subscription creation uses exactly one of planId or planCode.
  • Quota mutations identify the customer with exactly one of customerId or externalId.
  • Add-on fields must match the selected consumptionModel.
  • Portal sessions use exactly one of email or customerId.
  • Payout verification uses either the individual or company payload.
  • Test Clock updates use either advanceDays or frozenTime.

Direct API integrations must also move legacy /manage operations to their canonical resource paths, use PATCH for partial updates, and send Idempotency-Key for idempotent writes. SDK v8 already uses these routes.

Verify version boundaries

  • Search for an explicit commet-version header and decide whether it should move to 2026-07-24.
  • Check the organization's API version in Settings → Development → API Versions.
  • Repin webhook endpoints separately when you are ready for v8 webhook payloads.
  • Exercise create, retrieve, list, usage check, usage track, and webhook verification in sandbox.

Runtime behavior that did not change

  • Existing Currency Pricing remains valid; Markets are an additive pricing layer.
  • Omitting priceId keeps default price resolution.
  • Archiving a selected price hides it from new selection but does not break existing subscriptions.
  • Accepted Offer phases remain immutable snapshots.
  • v7 traffic remains compatible through the API-version engine.

See Offers, Introductory Offers, Promotional Offers, Regional pricing, and API versioning.

Developers

  • Documentation
  • Templates
  • GitHub

Frameworks

  • Next.js
  • Remix
  • Nuxt
  • SvelteKit
  • Astro
  • Express
  • Hono
  • Django
  • FastAPI

Resources

  • Blog
  • Changelog
  • Pricing

AI

  • Agents
  • MCP Server
  • Agent Skills
  • Claude Code
  • Codex
  • Cursor

Learn

  • Guides
  • Glossary
  • Solutions
  • Billing for AI Models
  • Comparison

Compare

  • Stripe alternative
  • Orb alternative
  • Recurly alternative
  • Paddle alternative
  • Chargebee alternative
  • Lago alternative

Company

  • About
  • Open Source
  • Terms
  • Privacy

Countries

  • Mexico
  • Argentina
  • Colombia
  • Chile
  • Peru
  • Ecuador
  • Uruguay
  • Paraguay
  • Bolivia
  • Panama
  • El Salvador
  • Brazil
System statusXLinkedInGitHub