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:
Use this method to add a free subscription to any customer in a Stripe, Chargebee, Recurly, Braintree, Google Play, App Store Connect, SaaSync or custom source.
If your customers are in a source outside this list, create a custom source. Within it, create customers with free subscriptions. Then merge those customers with the corresponding customers from your existing source.
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 free plan
For deeper segmentation with plan filters, create a free plan 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.
If the customer belongs to a Stripe, Chargebee, Recurly, Braintree, Google Play, App Store Connect or SaaSync source, set the handle_as_user_edit query parameter to true. Without it, the invoice may be deleted during a resync or reimport. This is not required for custom sources. Learn more.
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
When the customer upgrades to a paid plan, use the Import Invoices endpoint to create a paid invoice:
- Reference the
plan_uuidof your paid plan. - Use the same
subscription_external_idto treat the upgrade as a plan switch within the same subscription rather than a new subscription. - For paid subscriptions, a
service_period_endis required. - If the customer belongs to a Stripe, Chargebee, Recurly, Braintree, Google Play, App Store Connect or SaaSync source, set the
handle_as_user_editquery parameter totrue.
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_8c3f1b92",
"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_8c3f1b92",
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_8c3f1b92",
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_8c3f1b92",
"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_8c3f1b92",
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_8c3f1b92",
"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
When the customer downgrades to a free plan, use the Import Invoices endpoint to create a new zero-value invoice:
- Reference the
plan_uuidof your free plan. - Use the same
subscription_external_idto treat the downgrade as a plan switch within the same subscription rather than a new subscription. - A
service_period_endis optional for free subscriptions. - If the customer belongs to a Stripe, Chargebee, Recurly, Braintree, Google Play, App Store Connect or SaaSync source, set the
handle_as_user_editquery parameter totrue.
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_8c3f1b92",
"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_8c3f1b92",
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_8c3f1b92",
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_8c3f1b92",
"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_8c3f1b92",
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_8c3f1b92",
"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)