Plan Versioning

How ABAXUS handles pricing changes without breaking existing subscriptions.

Why Plans Are Immutable

Every ABAXUS price plan is versioned and immutable after creation. You cannot edit the charges, entitlements, or pricing tiers on a published plan version. This is intentional — and it’s the key design decision that makes billing safe to evolve.

When a customer subscribes, the subscription records the specific plan version number at that moment. All billing calculations for that subscription use that exact version, indefinitely. If you publish a new version with different pricing, existing subscriptions are unaffected. Only subscriptions you explicitly migrate will move to the new version.

This means:

  • Any historical invoice can be recalculated and will produce the same result
  • Customers on annual contracts won’t be surprised by mid-contract price changes
  • You can experiment with new pricing structures without fear of breaking existing billing

How to Update a Plan

To update a price plan, POST to the same endpoint with the same plan id:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
curl -X POST "$ABAXUS_URL/v1/price-plans" \
  -H "Authorization: Bearer $ABAXUS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "plan_growth",
    "name": "Growth",
    "currency": "usd",
    "billing_period": "monthly",
    "changelog": "Reduced per-call price above 1M. Free tier extended to 200k calls.",
    "charges": [
      {
        "metric_key": null,
        "pricing_model": "flat_fee",
        "amount": 49.00,
        "description": "Growth base fee"
      },
      {
        "metric_key": "api_calls",
        "pricing_model": "tiered",
        "tiers": [
          { "up_to": 200000, "unit_price": 0 },
          { "up_to": 1000000, "unit_price": 0.00009 },
          { "up_to": null, "unit_price": 0.00004 }
        ]
      }
    ]
  }'

ABAXUS returns the new version (e.g., version: 2) with status: active. The previous version automatically gets status: active removed but is not deprecated until you do so explicitly.


Key Version Fields

FieldDescription
versionInteger, auto-incremented. Version 1 is always the initial creation.
effective_fromISO timestamp. When this version becomes the default for new subscriptions. Defaults to the creation time.
changelogOptional free-text description of what changed and why. Surfaced in the dashboard and API responses.
deprecated_atSet when you deprecate a version. Deprecated versions cannot be selected for new subscriptions.
statusactive (current default), deprecated (still valid for existing subscriptions, not for new ones).

Deprecating a Version

To mark a version as deprecated so it cannot be selected for new subscriptions:

1
2
3
4
5
6
curl -X POST "$ABAXUS_URL/v1/price-plans/plan_growth/versions/1/deprecate" \
  -H "Authorization: Bearer $ABAXUS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "deprecated_at": "2026-05-01T00:00:00Z"
  }'

Deprecation is forward-looking. Any subscription already pinned to version 1 continues to use it. Deprecation only prevents new subscriptions from selecting that version. Existing subscriptions on a deprecated version will continue to bill correctly indefinitely.


Migrating Customers to New Versions

To move a customer to a new plan version, create a plan_change subscription amendment:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
curl -X POST "$ABAXUS_URL/v1/subscriptions/sub_01hx8km.../amendments" \
  -H "Authorization: Bearer $ABAXUS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "plan_change",
    "new_plan_id": "plan_growth",
    "new_plan_version": 2,
    "effective": "end_of_period",
    "prorate": false
  }'

Setting effective: "end_of_period" ensures the customer is migrated at their next natural renewal date, avoiding partial-period billing complexity. Setting effective: "immediate" migrates them now and prorates the remaining period if prorate: true.

See the Subscription Amendments guide for the full amendment lifecycle.


Best Practices

Use the changelog field. Every version update should include a human-readable description of what changed. This is surfaced in the dashboard and makes audit reviews much easier.

Deprecate old versions after migration. Once you’ve migrated all active subscriptions off a version, deprecate it to keep the version list clean. Deprecated versions remain in the system for historical reference.

Test in staging first. Create your new plan version in a staging environment, verify the pricing calculations with POST /v1/pricing/calculate, and then publish to production. The calculation API lets you preview invoices before any real money moves.