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:
- Create a source to store your subscription data
- Create a plan for your free subscription
- 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:
- Provide the
data_source_uuidof the source that stores your subscription data. - Specify the
nameandexternal_idfor the plan. - Set the
interval_unitandinterval_count. For example, a quarterly plan has aninterval_unitofmonthand aninterval_countof3.
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:
- Set the
typetosubscription. - Set the
amount_in_centsto0. - Set the
plan_uuidto the UUID of your free plan. - Use a unique
subscription_external_idfor ChartMogul to track the subscription over time. - Set the
service_period_startto the start date. - A
service_period_endis optional for zero-value subscription line items. Omit it for open-ended free subscriptions that remain active until the customer upgrades or cancels.
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:
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:
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:
- Subscriptions and Subscription History tables on customer profiles
- All Subscriptions, All Subscribers, Subscription Movements, Trial-to-Free-or-Paid Conversions and All Subscriber Churn Rate reports
- Filters such as Subscriber since or Plan (at subscription start)