Skip to main content
A subscription’s line items are the actual billing records — one per price. After a subscription is live, you can add new line items, update existing ones, remove them, or push plan-level pricing changes to all subscribers using the price sync workflow.

What Is a Line Item?

Each line item on a subscription:
  • References one price (price_id)
  • Has its own start_date and end_date
  • Is what the billing engine uses to generate invoice charges
  • Can point to a plan price (standard) or a subscription-scoped price (overridden)

Adding a Line Item

Use this when you want to add a charge that wasn’t part of the original subscription — for example, an add-on price or a usage meter you’ve just enabled.
If the price is usage-based, quantity is automatically set to 0 — usage is computed from metered events.

Updating a Line Item

Use this to change the pricing or quantity of an existing line item.
When you change pricing fields (amount, tiers, billing model), the system:
  1. Terminates the old line item at effective_from
  2. Creates a new subscription-scoped price with the updated values
  3. Creates a new line item starting at effective_from
When you only change metadata or commitment fields, the line item is updated in-place — no new price is created.

Removing a Line Item

Use this to stop billing for a specific charge.
This sets end_date on the line item. The line item record is retained for billing history. Billing stops at the effective date.

Pushing Plan Price Changes to Existing Subscriptions (Price Sync)

When you update a plan’s prices, existing subscriptions are not automatically updated. The price sync workflow propagates plan changes to all active subscribers on a plan.

What Sync Does

Phase 1 — Terminate expired line items: Finds line items for plan prices that have an end_date in the past. Sets line_item.end_date = price.end_date. Those charges stop billing. Phase 2 — Create missing line items: Finds plan prices that do not have a corresponding line item on each active subscription. Creates the missing line items with values from the plan price. What sync does NOT do:
  • Does not update line items that already exist
  • Does not overwrite line items with overridden (subscription-scoped) prices
  • Does not delete line items for plan prices that were removed (set price.end_date to stop billing for removed prices)
Step 1 — Update plan prices
Step 2 — Check for a running sync
If pagination.total > 0, a sync is already running. Wait for it before triggering a new one. Step 3 — Trigger sync
Response:
Step 4 — Poll until complete
Poll every 30 seconds. Check status in the response. Step 5 — Handle failure On Failed, call GET /workflows/{workflow_id}/{run_id} to review the error context and re-trigger after fixing the root cause.

Workflow Status Values

Date Handling

Line Item Start Date

The latest of the three applies. Timestamps are stored in UTC, truncated to milliseconds.

Line Item End Date

When Sync Creates Line Items

Sync uses the plan price’s dates directly: start_date = price.start_date, end_date = price.end_date. If the plan price has no dates, the created line item also has no dates (open-ended).

All Combinations

Validation

  • line_item.start_date >= subscription.start_date
  • line_item.end_date <= subscription.end_date (when subscription has one)
  • line_item.start_date <= line_item.end_date (when both set)

Decision Guide

Edge Cases & Gotchas

Overrides survive sync. Sync only creates items for missing (subscription_id, price_id) pairs. An overridden line item already exists (pointing to a subscription-scoped price), so sync never replaces it. Removing a plan price does not stop billing automatically. Sync has no delete phase. To stop billing for a plan price, set price.end_date. The sync termination phase will then close the line items. Prices without dates don’t expire. If a plan price has no start_date or end_date, line items created by sync have no date bounds and remain active until the subscription ends or you manually terminate them. Concurrent sync protection. The sync API uses a Redis distributed lock (2-hour TTL). Always check for a running workflow before triggering to avoid redundant runs. Usage prices always get quantity = 0. Setting quantity on a usage-based price override is rejected. Usage is computed from ingested events, not the line item quantity.