Skip to content

Manage subscriptions

Add a product to your subscription, upgrade or downgrade between plans, and drop products or cancel altogether. Your account has one subscription with an item per enrolled product — every change is a PUT that replaces the desired state, with an optional preview action that projects the effect first.

Prerequisites: You must be the OWNER. ADMINs can read billing but cannot make changes. You must have at least one payment method on file before enrolling your first paid item — see Manage payment methods.

The model in 60 seconds

  • Each product (audit, config, flags, logging) starts at the implicit Free plan. Products on Free are simply absent from the subscription — there is no item for them.
  • To move a product to a paid plan (STANDARD or PRO), include it in the items list of a PUT.
  • To downgrade or drop a product, send a PUT with that product at a lower plan or omit it from the list.
  • Every PUT is a full replace of the desired state: list every product you want enrolled (at the plan you want), even ones that aren't changing.
  • Plan names are SCREAMING_SNAKE_CASE on the wire (STANDARD, PRO, FREE); the server accepts any casing on input.

The server diffs against your current state. Adds and upgrades take effect immediately; downgrades and drops are scheduled for the end of the current billing period. You can preview the effect before committing.

Read the current subscription

bash
curl https://app.smplkit.com/api/v1/accounts/current/subscription \
  -H "Authorization: Bearer $SMPLKIT_API_KEY"

Returns 404 when you have no subscription yet — that's the from-scratch state where every product is at implicit Free. Once you have at least one paid item the endpoint returns the full resource:

json
{
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "type": "subscription",
    "attributes": {
      "status": "ACTIVE",
      "current_period_start": "2026-05-01T00:00:00Z",
      "current_period_end": "2026-06-01T00:00:00Z",
      "discount_pct": 15,
      "discount_source": "VOLUME",
      "subtotal_cents": 14800,
      "discount_amount_cents": 2220,
      "total_cents": 12580,
      "next_tier": {
        "products_needed": 1,
        "discount_pct": 33,
        "additional_savings_cents": 4281
      },
      "payment_method": "p1q2r3s4-5678-90ab-cdef-1234567890ab",
      "items": [
        {
          "id": "i1j2k3l4-5678-90ab-cdef-1234567890ab",
          "product": "logging",
          "plan": "STANDARD",
          "price_monthly_cents": 4900,
          "pending_plan_change": null,
          "scheduled_change_effective_at": null
        },
        {
          "id": "i2j3k4l5-6789-0abc-def1-234567890abc",
          "product": "config",
          "plan": "PRO",
          "price_monthly_cents": 9900,
          "pending_plan_change": null,
          "scheduled_change_effective_at": null
        }
      ]
    }
  }
}

Items with a scheduled change carry pending_plan_change (the plan they'll move to) and scheduled_change_effective_at (when it happens — always current_period_end).

Preview a change

Before committing any change, you can ask the platform to project it:

bash
curl -X POST https://app.smplkit.com/api/v1/accounts/current/subscription/actions/preview \
  -H "Authorization: Bearer $SMPLKIT_API_KEY" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "subscription",
      "attributes": {
        "items": [
          {"product": "logging", "plan": "STANDARD"},
          {"product": "config", "plan": "PRO"},
          {"product": "audit", "plan": "PRO"}
        ]
      }
    }
  }'

Returns the same items list re-projected, plus per-product changes (with effect: IMMEDIATE | NEXT_PERIOD and prorated_charge_today_cents), the new projected_discount_pct, total_charge_today_cents, and next_invoice_total_cents. No state is mutated; safe to call as the customer iterates on a plan picker.

Apply a change

Send the desired state with PUT. The server diffs and reconciles.

Add a product (or enroll your first paid item)

To enroll Logging at Standard when you previously had no subscription, or to add Audit to an existing subscription:

bash
curl -X PUT https://app.smplkit.com/api/v1/accounts/current/subscription \
  -H "Authorization: Bearer $SMPLKIT_API_KEY" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "subscription",
      "attributes": {
        "items": [
          {"product": "logging", "plan": "STANDARD"}
        ],
        "payment_method": "'$PAYMENT_METHOD_UUID'"
      }
    }
  }'

payment_method is the UUID of a payment method row in your account, not a Stripe ID. The field is optional — omit it to use the account's default payment method. If your subscription is moving from fully discounted to paying (or being created for the first time) and no default is configured, the request returns 400.

New items take effect immediately. Stripe creates prorations for the remainder of the current period.

Upgrade an existing item

Move a product to a higher plan within the same PUT by changing its plan value — and include every other item you want kept on the subscription:

bash
curl -X PUT https://app.smplkit.com/api/v1/accounts/current/subscription \
  -H "Authorization: Bearer $SMPLKIT_API_KEY" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "subscription",
      "attributes": {
        "items": [
          {"product": "logging", "plan": "PRO"}
        ]
      }
    }
  }'

Upgrades take effect immediately; the next invoice reflects the prorated charge.

Downgrade an item

Move a product to a lower paid plan. Downgrades are scheduled for the end of the current billing period — the higher plan continues until then.

bash
curl -X PUT https://app.smplkit.com/api/v1/accounts/current/subscription \
  -H "Authorization: Bearer $SMPLKIT_API_KEY" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "subscription",
      "attributes": {
        "items": [
          {"product": "logging", "plan": "STANDARD"}
        ]
      }
    }
  }'

The item appears in the response with pending_plan_change: "STANDARD" and scheduled_change_effective_at set to current_period_end.

Drop a product (move it back to Free)

To drop Logging entirely while keeping Config, send the PUT with only Config in the items list:

bash
curl -X PUT https://app.smplkit.com/api/v1/accounts/current/subscription \
  -H "Authorization: Bearer $SMPLKIT_API_KEY" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "subscription",
      "attributes": {
        "items": [
          {"product": "config", "plan": "PRO"}
        ]
      }
    }
  }'

The omitted item is scheduled for drop at period end. It appears in the response with pending_plan_change: "FREE" until then.

Cancel everything

Drop every product by sending an empty items list. Stripe schedules cancellation at period end; all items revert to Free then.

bash
curl -X PUT https://app.smplkit.com/api/v1/accounts/current/subscription \
  -H "Authorization: Bearer $SMPLKIT_API_KEY" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "subscription",
      "attributes": {"items": []}
    }
  }'

Reverse a pending downgrade or drop

There is no dedicated uncancel / undowngrade action. To reverse a pending change, send another PUT with the item back at its current paid plan (the one shown in plan, not the one in pending_plan_change). The diff classifies it as UNCHANGED and clears the pending change.

bash
# Item currently shows plan: "PRO", pending_plan_change: "STANDARD"
curl -X PUT https://app.smplkit.com/api/v1/accounts/current/subscription \
  -H "Authorization: Bearer $SMPLKIT_API_KEY" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "subscription",
      "attributes": {
        "items": [
          {"product": "logging", "plan": "PRO"}
        ]
      }
    }
  }'

In the console

  1. Go to AccountSubscriptions.
  2. Adjust each product's plan via the picker.
  3. The page shows a live preview — per-item effect (immediate vs scheduled), prorated charge today, and the projected next-invoice total — driven by the /actions/preview endpoint.
  4. Click Confirm to apply.

Subscription statuses

The status field reflects Stripe's view of billing health:

  • ACTIVE — billing is current.
  • PAST_DUE — last invoice failed; Stripe is retrying. Functionality continues during the retry window.
  • CANCELED — subscription has ended. Functionality continues until current_period_end, then drops to Free.
  • null — the subscription is fully discounted via a 100% administrator override; Stripe is not involved.

Resolve a past-due subscription by adding or updating a payment method (see Manage payment methods). Stripe automatically retries on the next billing event.

Verify

After any change:

bash
curl https://app.smplkit.com/api/v1/accounts/current/subscription \
  -H "Authorization: Bearer $SMPLKIT_API_KEY"

Confirm each item shows the expected plan (and, if applicable, pending_plan_change / scheduled_change_effective_at). The console Subscriptions page reflects the same data.

If you upgraded, try a write that previously hit the entitlement cap — it should now succeed.