Zum Hauptinhalt springen
This guide shows you how to implement self-service upgrades and downgrades using product groups in your application.

Overview

The upgrade/downgrade flow consists of three main steps:
  1. Check eligibility - Get available change options for a subscription item
  2. Display options - Show the customer available upgrades/downgrades
  3. Apply change - Execute the selected package change

Prerequisites

Before implementing upgrades:
  1. Create a Product Group with a tier for each package level
  2. Assign the product group to the subscription item via PUT /subscription-items/{id}/product-group

Step 1: Get Change Options

Fetch available upgrade/downgrade options for a subscription item:
curl -X GET "https://coreapi.io/subscription-items/{itemId}/change-options" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "current": {
    "id": "tier-starter-uuid",
    "name": "Starter Plan",
    "pricePlan": {
      "id": "price-starter-uuid",
      "name": "Starter Monthly",
      "price": 2900,
      "billingInterval": "monthly"
    },
    "product": {
      "id": "product-starter-uuid",
      "name": "Starter"
    }
  },
  "options": [
    {
      "id": "tier-pro-uuid",
      "label": "Pro",
      "product": {
        "id": "product-pro-uuid",
        "name": "Pro Plan"
      },
      "pricePlans": [
        {
          "id": "price-pro-monthly-uuid",
          "name": "Pro Monthly",
          "price": 4900,
          "billingInterval": "monthly"
        }
      ],
      "changeTiming": "immediately",
      "creditType": "pro_rata",
      "isUpgrade": true,
      "isDowngrade": false,
      "quantitySetting": null
    }
  ],
  "hasPendingChange": false
}

Response Fields

FieldDescription
currentCurrently active tier and price plan
optionsAvailable upgrade/downgrade options
options[].isUpgradetrue if this is an upgrade
options[].isDowngradetrue if this is a downgrade
options[].changeTimingWhen the change takes effect
options[].creditTypeHow unused time is credited
hasPendingChangetrue if a change is already scheduled
If hasPendingChange is true, no further changes can be made until the pending change is applied.

Step 2: Display Options to Customer

Use the response to build a selection UI:
async function getUpgradeOptions(subscriptionItemId) {
  const response = await fetch(
    `/subscription-items/${subscriptionItemId}/change-options`,
    { headers: { Authorization: `Bearer ${token}` } }
  );

  const data = await response.json();

  // Check if changes are possible
  if (data.hasPendingChange) {
    return { error: 'A change is already pending' };
  }

  if (data.options.length === 0) {
    return { error: 'No upgrade options available' };
  }

  // Separate upgrades and downgrades
  const upgrades = data.options.filter(o => o.isUpgrade);
  const downgrades = data.options.filter(o => o.isDowngrade);

  return { current: data.current, upgrades, downgrades };
}

Step 3: Apply the Change

When the customer selects an option, apply the change:
curl -X POST "https://coreapi.io/product-group-memberships/{tierId}/apply" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "subscriptionItem": "subscription-item-uuid",
    "quantity": 1
  }'

Request Parameters

ParameterTypeRequiredDescription
subscriptionItemstringYesUUID of the subscription item to change
selectedPricePlanstringNoUUID of the price plan. Only required if the tier has multiple price plans. In most cases, this can be omitted.
quantityintegerNoNew quantity. Only applied if the tier allows quantity changes.
sendInvoiceEmailbooleanNoSend credit note via email (default: true)

Response

{
  "subscriptionItem": {
    "id": "item-uuid",
    "product": { "id": "...", "name": "Pro Plan" },
    "pricePlan": { "id": "...", "name": "Pro Monthly" },
    "status": "active"
  },
  "creditNote": {
    "id": "credit-note-uuid",
    "number": "CN-2026-0001",
    "amount": 1450
  }
}

Change Timing Behavior

Immediately

The change takes effect right away:
  1. Current subscription item is ended
  2. Credit note is created (based on creditType)
  3. New subscription item is created and starts immediately
  4. New invoice is generated

End of Period

The change is scheduled for the next billing cycle:
  1. Current subscription item continues until period end
  2. At period end, item switches to new product/plan
  3. No credit note is created
  4. Next invoice uses new pricing

Credit Types

When changeTiming is immediately, a credit is issued based on creditType:
TypeFormulaExample
pro_rataPrice × (Days remaining / Days in period)€29 × (15/30) = €14.50
fullFull period price€29.00
last_invoicedAmount from last invoiceVaries
noneNo credit€0.00

Complete Example

async function upgradeSubscription(subscriptionItemId, targetTierId) {
  // 1. Get current options to validate
  const options = await fetch(
    `/subscription-items/${subscriptionItemId}/change-options`,
    { headers: { Authorization: `Bearer ${token}` } }
  ).then(r => r.json());

  if (options.hasPendingChange) {
    throw new Error('Cannot change: pending change exists');
  }

  // 2. Find the selected option
  const selectedOption = options.options.find(o => o.id === targetTierId);
  if (!selectedOption) {
    throw new Error('Invalid tier selected');
  }

  // 3. Apply the change
  const result = await fetch(
    `/product-group-memberships/${targetTierId}/apply`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`
      },
      body: JSON.stringify({
        subscriptionItem: subscriptionItemId,
        quantity: 1
      })
    }
  ).then(r => r.json());

  return {
    newItem: result.subscriptionItem,
    creditNote: result.creditNote
  };
}

Error Handling

HTTP StatusCauseSolution
400Invalid requestCheck required fields
404Subscription item not foundVerify item UUID
422Pending change existsWait for pending change to complete
422Not eligible for changeCheck tier eligibility settings

Webhooks

Listen for these events to track changes:
EventDescription
subscription.updatedSubscription items changed
invoice.createdNew invoice for upgraded subscription
credit_note.createdCredit note for prorated amount