Tracking free subscriptions

This tutorial describes how to track free and freemium subscriptions in ChartMogul using the API.

If your product has a free plan or freemium tier, ChartMogul allows you to track those subscriptions the same way you track paid plans.

To create a free subscription:

  1. Create a source to store your subscription data
  2. Create a plan for your free subscription
  3. Create an invoice with a zero-value line item

Gradual rollout. We introduced the ability to track free subscriptions on October 2, 2025, and are making it gradually available to all accounts. If you can see the All Subscriptions chart in the app, it means you can track free subscriptions.

Creating a source

If you don’t have a source to store your subscription data, create one. Use the same source for your paid and free subscriptions.

Use the Create a Source endpoint:

curl -X POST "https://api.chartmogul.com/v1/data_sources" \
     -u YOUR_API_KEY: \
     -H "Content-Type: application/json" \
     -d{
            "name": "Custom source"
         }
ChartMogul::DataSource.create!(name: "Custom source")
ChartMogul.DataSource.create(config, {
  name: "Custom source",
});
ChartMogul\DataSource::create([
  "name" => "Custom source"
]);
api.CreateDataSource("Custom source")
chartmogul.DataSource.create(config, data={"name": "Custom source"})

Use the data_source_uuid from the response in the following steps.

Creating a free plan

If you don’t have a plan for your free subscriptions, add one using the Create a Plan endpoint:

curl -X POST "https://api.chartmogul.com/v1/plans" \
     -u YOUR_API_KEY: \
     -H "Content-Type: application/json" \
     -d '{
           "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
           "name": "Free",
           "interval_count": 1,
           "interval_unit": "month",
           "external_id": "plan_free"
         }'
ChartMogul::Import::Plan.create!(
  data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  name: "Free",
  interval_count: 1,
  interval_unit: "month",
  external_id: "plan_free",
)
ChartMogul.Plan.create(config, {
  data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  name: "Free",
  interval_count: 1,
  interval_unit: "month",
  external_id: "plan_free",
});
ChartMogul\Import\Plan::create([
  "data_source_uuid" => "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  "name" => "Free",
  "interval_count" => 1,
  "interval_unit" => "month",
  "external_id" => "plan_free"
]);
api.CreatePlan(&cm.Plan{
  DataSourceUUID: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  Name:           "Free",
  IntervalCount:  1,
  IntervalUnit:   "month",
  ExternalID:     "plan_free",
})
chartmogul.Plan.create(
  config,
  data={
    "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
    "name": "Free",
    "interval_count": 1,
    "interval_unit": "month",
    "external_id": "plan_free",
  },
)

Use the plan_uuid from the response when creating free subscription invoices.

Creating a free subscription invoice

Use the Import Invoices endpoint to create an invoice with a zero-value subscription line item:

curl -X POST "https://api.chartmogul.com/v1/import/customers/cus_f466e33d-ff2b-4a11-8f85-417eb02157a7/invoices" \
     -u YOUR_API_KEY: \
     -H "Content-Type: application/json" \
     -d '{
            "invoices": [
              {
                "external_id": "inv_5b3e9c72",
                "date": "2026-01-10",
                "currency": "USD",
                "customer_external_id": "cus_7f9e2a41",
                "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
                "line_items": [
                  {
                    "type": "subscription",
                    "subscription_external_id": "sub_8c3f1b92",
                    "plan_uuid": "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
                    "service_period_start": "2026-01-10",
                    "amount_in_cents": 0,
                    "quantity": 1
                  }
                ]
              }
            ]
        }'
line_item = ChartMogul::LineItems::Subscription.new(
  subscription_external_id: "sub_8c3f1b92",
  plan_uuid: "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
  service_period_start: Time.utc(2026, 1, 10),
  amount_in_cents: 0,
  quantity: 1,
)

invoice = ChartMogul::Invoice.new(
  external_id: "inv_5b3e9c72",
  date: Time.utc(2026, 1, 10),
  currency: "USD",
  customer_external_id: "cus_7f9e2a41",
  data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  line_items: [line_item],
)

ChartMogul::CustomerInvoices.create!(
  customer_uuid: "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
  invoices: [invoice],
)
ChartMogul.Invoice.create(config, "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7", {
  invoices: [
    {
      external_id: "inv_5b3e9c72",
      date: "2026-01-10",
      currency: "USD",
      customer_external_id: "cus_7f9e2a41",
      data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
      line_items: [
        {
          type: "subscription",
          subscription_external_id: "sub_8c3f1b92",
          plan_uuid: "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
          service_period_start: "2026-01-10",
          amount_in_cents: 0,
          quantity: 1,
        },
      ],
    },
  ],
});
$line_item = new ChartMogul\LineItems\Subscription([
  "subscription_external_id" => "sub_8c3f1b92",
  "plan_uuid" => "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
  "service_period_start" => "2026-01-10",
  "amount_in_cents" => 0,
  "quantity" => 1
]);

$invoice = new ChartMogul\Invoice([
  "external_id" => "inv_5b3e9c72",
  "date" => "2026-01-10",
  "currency" => "USD",
  "customer_external_id" => "cus_7f9e2a41",
  "data_source_uuid" => "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  "line_items" => [$line_item]
]);

ChartMogul\CustomerInvoices::create([
  "customer_uuid" => "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
  "invoices" => [$invoice]
]);
lineItem := &cm.LineItem{
  Type:                   "subscription",
  SubscriptionExternalID: "sub_8c3f1b92",
  PlanUUID:               "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
  ServicePeriodStart:     "2026-01-10",
  AmountInCents:          0,
  Quantity:               1,
}

invoice := &cm.Invoice{
  ExternalID:         "inv_5b3e9c72",
  Date:               "2026-01-10",
  Currency:           "USD",
  CustomerExternalID: "cus_7f9e2a41",
  DataSourceUUID:     "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  LineItems:          []*cm.LineItem{lineItem},
}

api.CreateInvoices(
  []*cm.Invoice{invoice},
  "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
)
chartmogul.Invoice.create(
  config,
  uuid="cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
  data={
    "invoices": [
      {
        "external_id": "inv_5b3e9c72",
        "date": datetime(2026, 1, 10),
        "currency": "USD",
        "customer_external_id": "cus_7f9e2a41",
        "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
        "line_items": [
          {
            "type": "subscription",
            "subscription_external_id": "sub_8c3f1b92",
            "plan_uuid": "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
            "service_period_start": datetime(2026, 1, 10),
            "amount_in_cents": 0,
            "quantity": 1,
          }
        ],
      }
    ]
  },
)

Upgrading to a paid plan

Treat an upgrade to a paid plan as a new paid subscription starting on the upgrade date:

  1. Cancel the free subscription
  2. Create the first paid invoice

Canceling the free subscription

Use the Create a Subscription Event endpoint with the event_type set to subscription_cancelled and effective_date set to the upgrade date. Reference the subscription_external_id of your free subscription.

curl -X POST "https://api.chartmogul.com/v1/subscription_events" \
     -u YOUR_API_KEY: \
     -H "Content-Type: application/json" \
     -d '{
            "subscription_event": {
              "customer_external_id": "cus_7f9e2a41",
              "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
              "event_date": "2026-02-10",
              "effective_date": "2026-02-10",
              "event_type": "subscription_cancelled",
              "subscription_external_id": "sub_8c3f1b92"
            }
        }'
ChartMogul::SubscriptionEvent.create!(
  customer_external_id: "cus_7f9e2a41",
  data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  event_date: "2026-02-10",
  effective_date: "2026-02-10",
  event_type: "subscription_cancelled",
  subscription_external_id: "sub_8c3f1b92",
)
ChartMogul.SubscriptionEvent.create(config, {
  subscription_event: {
    customer_external_id: "cus_7f9e2a41",
    data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
    event_date: "2026-02-10",
    effective_date: "2026-02-10",
    event_type: "subscription_cancelled",
    subscription_external_id: "sub_8c3f1b92",
  },
});
ChartMogul\SubscriptionEvent::create([
  "subscription_event" => [
    "customer_external_id" => "cus_7f9e2a41",
    "data_source_uuid" => "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
    "event_date" => "2026-02-10",
    "effective_date" => "2026-02-10",
    "event_type" => "subscription_cancelled",
    "subscription_external_id" => "sub_8c3f1b92",
  ]
]);
api.CreateSubscriptionEvent(&cm.SubscriptionEvent{
  CustomerExternalID:     "cus_7f9e2a41",
  DataSourceUUID:         "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  EventDate:              "2026-02-10",
  EffectiveDate:          "2026-02-10",
  EventType:              "subscription_cancelled",
  SubscriptionExternalID: "sub_8c3f1b92",
})
chartmogul.SubscriptionEvent.create(
  config,
  data={
    "subscription_event": {
      "customer_external_id": "cus_7f9e2a41",
      "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
      "event_date": datetime(2026, 2, 10),
      "effective_date": datetime(2026, 2, 10),
      "event_type": "subscription_cancelled",
      "subscription_external_id": "sub_8c3f1b92",
    }
  },
)

Creating the first paid invoice

Use the Import Invoices endpoint to create the first paid invoice with a new subscription_external_id and the plan_uuid of your paid plan. This way ChartMogul knows that a new paid subscription is starting from the upgrade date.

For paid subscriptions, a service_period_end is required.

curl -X POST "https://api.chartmogul.com/v1/import/customers/cus_f466e33d-ff2b-4a11-8f85-417eb02157a7/invoices" \
     -u YOUR_API_KEY: \
     -H "Content-Type: application/json" \
     -d '{
            "invoices": [
              {
                "external_id": "inv_1d8f4e61",
                "date": "2026-02-10",
                "currency": "USD",
                "customer_external_id": "cus_7f9e2a41",
                "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
                "line_items": [
                  {
                    "type": "subscription",
                    "subscription_external_id": "sub_4e7d6a85",
                    "plan_uuid": "pl_aab05d54-75b4-431b-adb2-eb6b9e543207",
                    "service_period_start": "2026-02-10",
                    "service_period_end": "2026-03-10",
                    "amount_in_cents": 5000,
                    "quantity": 1
                  }
                ]
              }
            ]
        }'
line_item = ChartMogul::LineItems::Subscription.new(
  subscription_external_id: "sub_4e7d6a85",
  plan_uuid: "pl_aab05d54-75b4-431b-adb2-eb6b9e543207",
  service_period_start: Time.utc(2026, 2, 10),
  service_period_end: Time.utc(2026, 3, 10),
  amount_in_cents: 5000,
  quantity: 1,
)

invoice = ChartMogul::Invoice.new(
  external_id: "inv_1d8f4e61",
  date: Time.utc(2026, 2, 10),
  currency: "USD",
  customer_external_id: "cus_7f9e2a41",
  data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  line_items: [line_item],
)

ChartMogul::CustomerInvoices.create!(
  customer_uuid: "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
  invoices: [invoice],
)
ChartMogul.Invoice.create(config, "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7", {
  invoices: [
    {
      external_id: "inv_1d8f4e61",
      date: "2026-02-10",
      currency: "USD",
      customer_external_id: "cus_7f9e2a41",
      data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
      line_items: [
        {
          type: "subscription",
          subscription_external_id: "sub_4e7d6a85",
          plan_uuid: "pl_aab05d54-75b4-431b-adb2-eb6b9e543207",
          service_period_start: "2026-02-10",
          service_period_end: "2026-03-10",
          amount_in_cents: 5000,
          quantity: 1,
        },
      ],
    },
  ],
});
$line_item = new ChartMogul\LineItems\Subscription([
  "subscription_external_id" => "sub_4e7d6a85",
  "plan_uuid" => "pl_aab05d54-75b4-431b-adb2-eb6b9e543207",
  "service_period_start" => "2026-02-10",
  "service_period_end" => "2026-03-10",
  "amount_in_cents" => 5000,
  "quantity" => 1
]);

$invoice = new ChartMogul\Invoice([
  "external_id" => "inv_1d8f4e61",
  "date" => "2026-02-10",
  "currency" => "USD",
  "customer_external_id" => "cus_7f9e2a41",
  "data_source_uuid" => "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  "line_items" => [$line_item]
]);

ChartMogul\CustomerInvoices::create([
  "customer_uuid" => "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
  "invoices" => [$invoice]
]);
lineItem := &cm.LineItem{
  Type:                   "subscription",
  SubscriptionExternalID: "sub_4e7d6a85",
  PlanUUID:               "pl_aab05d54-75b4-431b-adb2-eb6b9e543207",
  ServicePeriodStart:     "2026-02-10",
  ServicePeriodEnd:       "2026-03-10",
  AmountInCents:          5000,
  Quantity:               1,
}

invoice := &cm.Invoice{
  ExternalID:         "inv_1d8f4e61",
  Date:               "2026-02-10",
  Currency:           "USD",
  CustomerExternalID: "cus_7f9e2a41",
  DataSourceUUID:     "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  LineItems:          []*cm.LineItem{lineItem},
}

api.CreateInvoices(
  []*cm.Invoice{invoice},
  "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
)
chartmogul.Invoice.create(
  config,
  uuid="cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
  data={
    "invoices": [
      {
        "external_id": "inv_1d8f4e61",
        "date": datetime(2026, 2, 10),
        "currency": "USD",
        "customer_external_id": "cus_7f9e2a41",
        "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
        "line_items": [
          {
            "type": "subscription",
            "subscription_external_id": "sub_4e7d6a85",
            "plan_uuid": "pl_aab05d54-75b4-431b-adb2-eb6b9e543207",
            "service_period_start": datetime(2026, 2, 10),
            "service_period_end": datetime(2026, 3, 10),
            "amount_in_cents": 5000,
            "quantity": 1,
          }
        ],
      }
    ]
  },
)

Downgrading to a free plan

Treat a downgrade from a paid plan to a free one as a new free subscription starting on the downgrade date:

  1. Cancel the paid subscription
  2. Create the first free invoice

Canceling the paid subscription

Use the Create a Subscription Event endpoint with the event_type set to subscription_cancelled and effective_date set to the downgrade date. Reference the subscription_external_id of your paid subscription.

curl -X POST "https://api.chartmogul.com/v1/subscription_events" \
     -u YOUR_API_KEY: \
     -H "Content-Type: application/json" \
     -d '{
            "subscription_event": {
              "customer_external_id": "cus_7f9e2a41",
              "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
              "event_date": "2026-03-10",
              "effective_date": "2026-03-10",
              "event_type": "subscription_cancelled",
              "subscription_external_id": "sub_4e7d6a85"
            }
        }'
ChartMogul::SubscriptionEvent.create!(
  customer_external_id: "cus_7f9e2a41",
  data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  event_date: "2026-03-10",
  effective_date: "2026-03-10",
  event_type: "subscription_cancelled",
  subscription_external_id: "sub_4e7d6a85",
)
ChartMogul.SubscriptionEvent.create(config, {
  subscription_event: {
    customer_external_id: "cus_7f9e2a41",
    data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
    event_date: "2026-03-10",
    effective_date: "2026-03-10",
    event_type: "subscription_cancelled",
    subscription_external_id: "sub_4e7d6a85",
  },
});
ChartMogul\SubscriptionEvent::create([
  "subscription_event" => [
    "customer_external_id" => "cus_7f9e2a41",
    "data_source_uuid" => "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
    "event_date" => "2026-03-10",
    "effective_date" => "2026-03-10",
    "event_type" => "subscription_cancelled",
    "subscription_external_id" => "sub_4e7d6a85",
  ]
]);
api.CreateSubscriptionEvent(&cm.SubscriptionEvent{
  CustomerExternalID:     "cus_7f9e2a41",
  DataSourceUUID:         "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  EventDate:              "2026-03-10",
  EffectiveDate:          "2026-03-10",
  EventType:              "subscription_cancelled",
  SubscriptionExternalID: "sub_4e7d6a85",
})
chartmogul.SubscriptionEvent.create(
  config,
  data={
    "subscription_event": {
      "customer_external_id": "cus_7f9e2a41",
      "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
      "event_date": datetime(2026, 3, 10),
      "effective_date": datetime(2026, 3, 10),
      "event_type": "subscription_cancelled",
      "subscription_external_id": "sub_4e7d6a85",
    }
  },
)

Creating the first free invoice

Use the Import Invoices endpoint to create a new zero-value invoice with a new subscription_external_id (different from the original free subscription). Reference the plan_uuid of your free plan. This way ChartMogul knows that a new free subscription is starting from the downgrade date.

curl -X POST "https://api.chartmogul.com/v1/import/customers/cus_f466e33d-ff2b-4a11-8f85-417eb02157a7/invoices" \
     -u YOUR_API_KEY: \
     -H "Content-Type: application/json" \
     -d '{
            "invoices": [
              {
                "external_id": "inv_6a2c8b37",
                "date": "2026-03-10",
                "currency": "USD",
                "customer_external_id": "cus_7f9e2a41",
                "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
                "line_items": [
                  {
                    "type": "subscription",
                    "subscription_external_id": "sub_2a9c5f13",
                    "plan_uuid": "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
                    "service_period_start": "2026-03-10",
                    "amount_in_cents": 0,
                    "quantity": 1
                  }
                ]
              }
            ]
        }'
line_item = ChartMogul::LineItems::Subscription.new(
  subscription_external_id: "sub_2a9c5f13",
  plan_uuid: "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
  service_period_start: Time.utc(2026, 3, 10),
  amount_in_cents: 0,
  quantity: 1,
)

invoice = ChartMogul::Invoice.new(
  external_id: "inv_6a2c8b37",
  date: Time.utc(2026, 3, 10),
  currency: "USD",
  customer_external_id: "cus_7f9e2a41",
  data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  line_items: [line_item],
)

ChartMogul::CustomerInvoices.create!(
  customer_uuid: "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
  invoices: [invoice],
)
ChartMogul.Invoice.create(config, "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7", {
  invoices: [
    {
      external_id: "inv_6a2c8b37",
      date: "2026-03-10",
      currency: "USD",
      customer_external_id: "cus_7f9e2a41",
      data_source_uuid: "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
      line_items: [
        {
          type: "subscription",
          subscription_external_id: "sub_2a9c5f13",
          plan_uuid: "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
          service_period_start: "2026-03-10",
          amount_in_cents: 0,
          quantity: 1,
        },
      ],
    },
  ],
});
$line_item = new ChartMogul\LineItems\Subscription([
  "subscription_external_id" => "sub_2a9c5f13",
  "plan_uuid" => "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
  "service_period_start" => "2026-03-10",
  "amount_in_cents" => 0,
  "quantity" => 1
]);

$invoice = new ChartMogul\Invoice([
  "external_id" => "inv_6a2c8b37",
  "date" => "2026-03-10",
  "currency" => "USD",
  "customer_external_id" => "cus_7f9e2a41",
  "data_source_uuid" => "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  "line_items" => [$line_item]
]);

ChartMogul\CustomerInvoices::create([
  "customer_uuid" => "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
  "invoices" => [$invoice]
]);
lineItem := &cm.LineItem{
  Type:                   "subscription",
  SubscriptionExternalID: "sub_2a9c5f13",
  PlanUUID:               "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
  ServicePeriodStart:     "2026-03-10",
  AmountInCents:          0,
  Quantity:               1,
}

invoice := &cm.Invoice{
  ExternalID:         "inv_6a2c8b37",
  Date:               "2026-03-10",
  Currency:           "USD",
  CustomerExternalID: "cus_7f9e2a41",
  DataSourceUUID:     "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
  LineItems:          []*cm.LineItem{lineItem},
}

api.CreateInvoices(
  []*cm.Invoice{invoice},
  "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
)
chartmogul.Invoice.create(
  config,
  uuid="cus_f466e33d-ff2b-4a11-8f85-417eb02157a7",
  data={
    "invoices": [
      {
        "external_id": "inv_6a2c8b37",
        "date": datetime(2026, 3, 10),
        "currency": "USD",
        "customer_external_id": "cus_7f9e2a41",
        "data_source_uuid": "ds_fef05d54-47b4-431b-aed2-eb6b9e545430",
        "line_items": [
          {
            "type": "subscription",
            "subscription_external_id": "sub_2a9c5f13",
            "plan_uuid": "pl_eed05d54-75b4-431b-adb2-eb6b9e543206",
            "service_period_start": datetime(2026, 3, 10),
            "amount_in_cents": 0,
            "quantity": 1,
          }
        ],
      }
    ]
  },
)

Where the data appears

Once imported, free subscriptions appear in: