Subscriptions With Pricing Models
Advanced Subscriptions
Advanced subscriptions let merchants build plans from the product catalog instead of a single fixed amount. A plan can combine multiple catalog products, support usage-based billing, and apply advanced pricing models such as volume with minimum spend (volume_minimum).
Use advanced subscriptions when you need:
- Multiple products on one recurring plan
- Pay-per-use billing reported via the Usage Records API
- Tiered usage pricing with a minimum charge per billing period
- Catalog-backed subscription templates and payment links
IMPORTANTTo follow the steps below, you must have a valid Authorization Token. For more information, refer to: Authorization Token
Overview
Standard vs advanced
| Standard subscription | Advanced subscription | |
|---|---|---|
| Pricing | Single amount + service | One or more catalog items[] |
| Usage billing | Not supported | Supported via usage_records |
| Amount at creation | Required | Derived from catalog prices (can be 0 for usage-only plans) |
| Interval | Set in request | Derived from catalog prices (all items must share the same interval) |
| Price snapshot | N/A | Stored on each item at creation time |
Supported pricing models on catalog prices
pricing_model | Metered required | Billing behavior |
|---|---|---|
standard | No | Fixed recurring charge from unit_amount |
standard | Yes | Usage charge = quantity × metered_unit_amount |
volume_minimum | Yes | Usage charge = MAX(total_quantity × tier.unit_rate, tier.minimum_spend) |
Note
volume_minimumalways requiresmetered: trueand apricing_model_config.volume_tiersarray on the product price. The applicable tier is selected from total period usage, not per individual usage record.
Create a Usage-Based Product Price
Before creating an advanced subscription, define the catalog product and its recurring price.
Visit our API Reference to create a product price.
Endpoint
POST https://ecartpay.com/api/products/:product_id/pricesPOST https://sandbox.ecartpay.com/api/products/:product_id/prices
Headers
Authorization: tokenContent-Type: application/json
Path parameters
product_id— Catalog product ID
Body — standard usage-based price
{
"type": "recurring",
"currency": "MXN",
"unit_amount": 0,
"billing_interval": "monthly",
"metered": true,
"metered_unit_amount": 0.05,
"metered_unit_label": "API call",
"pricing_model": "standard"
}Body — volume with minimum spend
{
"type": "recurring",
"currency": "MXN",
"unit_amount": 0,
"billing_interval": "monthly",
"metered": true,
"metered_unit_label": "transaction",
"pricing_model": "volume_minimum",
"pricing_model_config": {
"volume_tiers": [
{
"min_quantity": 1,
"max_quantity": 10000,
"unit_rate": 0.01,
"minimum_spend": 20
},
{
"min_quantity": 10001,
"max_quantity": null,
"unit_rate": 0.003,
"minimum_spend": 100
}
]
}
}Examples
Request
curl --request POST \
--url 'https://sandbox.ecartpay.com/api/products/68a4c3150b28a9584305a2a6/prices' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN' \
--header 'content-type: application/json' \
--data '{
"type": "recurring",
"currency": "MXN",
"unit_amount": 0,
"billing_interval": "monthly",
"metered": true,
"metered_unit_label": "transaction",
"pricing_model": "volume_minimum",
"pricing_model_config": {
"volume_tiers": [
{
"min_quantity": 1,
"max_quantity": 10000,
"unit_rate": 0.01,
"minimum_spend": 20
},
{
"min_quantity": 10001,
"max_quantity": null,
"unit_rate": 0.003,
"minimum_spend": 100
}
]
}
}'Response
{
"id": "68f1a2b3c4d5e6f7a8b9c0d1",
"product_id": "68a4c3150b28a9584305a2a6",
"type": "recurring",
"currency": "MXN",
"unit_amount": 0,
"billing_interval": "monthly",
"metered": true,
"metered_unit_label": "transaction",
"pricing_model": "volume_minimum",
"pricing_model_config": {
"volume_tiers": [
{
"min_quantity": 1,
"max_quantity": 10000,
"unit_rate": 0.01,
"minimum_spend": 20
},
{
"min_quantity": 10001,
"max_quantity": null,
"unit_rate": 0.003,
"minimum_spend": 100
}
]
},
"active": true
}Create Advanced Subscription Template
Subscription templates define reusable plans. When items[] is provided, amount, currency, interval, and service are resolved automatically from the catalog.
Visit our API Reference to create a subscription template.
Endpoint
POST https://ecartpay.com/api/subscriptions-templatePOST https://sandbox.ecartpay.com/api/subscriptions-template
Headers
Authorization: tokenContent-Type: application/json
Body
frequency— Billing frequency multiplier (required)items— Catalog line items (see structure below)trial_period_days— Optional trial periodbilling_cycle— Optional fixed billing day/monthbenefits— Optional list of plan benefitsmerchant_management— Optional checkout management flagredirect_url— Required whenmerchant_managementistrue
items[] structure
items[] structure| Field | Required | Description |
|---|---|---|
product_id | Yes | Catalog product ID |
price_id | Yes | Recurring product price ID |
quantity | No | Must be 1 when provided |
name | No | Optional snapshot override |
sku | No | Optional snapshot override |
unit_label | No | Optional snapshot override |
ImportantAll items must use recurring prices with the same billing interval. Mixing
monthlyandyearlyprices on the same plan is rejected.
Examples
Request — fixed + usage-based catalog plan
curl --request POST \
--url 'https://sandbox.ecartpay.com/api/subscriptions-template' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN' \
--header 'content-type: application/json' \
--data '{
"frequency": 1,
"trial_period_days": 7,
"benefits": [
"Platform access",
"Usage-based API billing"
],
"items": [
{
"product_id": "68a4c3150b28a9584305a2a6",
"price_id": "68f1a2b3c4d5e6f7a8b9c0d1"
},
{
"product_id": "68b1d2e3f4a5b6c7d8e9f001",
"price_id": "68f2b3c4d5e6f7a8b9c0d2"
}
]
}'Response
{
"id": "68f3c4d5e6f7a8b9c0d3e4",
"status": "active",
"link_enabled": true,
"payment_link": "https://sandbox.ecartpay.com/subscription_payment_link/68f3c4d5e6f7a8b9c0d3e4",
"amount": 499,
"currency": "MXN",
"interval": "monthly",
"frequency": 1,
"service": "Platform Access",
"trial_period_days": 7,
"items": [
{
"product_id": "68a4c3150b28a9584305a2a6",
"price_id": "68f1a2b3c4d5e6f7a8b9c0d1",
"quantity": 1,
"name": "Platform Access",
"metered": false,
"price_snapshot": {
"unit_amount": 499,
"currency": "MXN",
"type": "recurring",
"pricing_model": "standard",
"billing_interval": "monthly"
}
},
{
"product_id": "68b1d2e3f4a5b6c7d8e9f001",
"price_id": "68f2b3c4d5e6f7a8b9c0d2",
"quantity": 1,
"name": "API Usage",
"unit_label": "transaction",
"metered": true,
"price_snapshot": {
"unit_amount": 0,
"currency": "MXN",
"type": "recurring",
"pricing_model": "volume_minimum",
"metered_unit_label": "transaction",
"billing_interval": "monthly",
"pricing_model_config": {
"volume_tiers": [
{
"min_quantity": 1,
"max_quantity": 10000,
"unit_rate": 0.01,
"minimum_spend": 20
},
{
"min_quantity": 10001,
"max_quantity": null,
"unit_rate": 0.003,
"minimum_spend": 100
}
]
}
}
}
],
"created_at": "2026-06-17T18:00:00.000Z",
"updated_at": "2026-06-17T18:00:00.000Z"
}Create Advanced Subscription
Create a subscription directly from catalog items, or from a template using template_id.
Visit our API Reference to create a subscription.
Endpoint
POST https://ecartpay.com/api/subscriptionsPOST https://sandbox.ecartpay.com/api/subscriptions
Headers
Authorization: tokenContent-Type: application/json
Body
customer_id— Required customer IDtemplate_id— Optional template ID (alternative to manualitems[])items— Optional catalog line itemscard_ids— Optional payment methods (1–5)trial_period_days— Optional trial periodbilling_cycle— Optional billing anchorbenefits— Optional benefit list
When items[] is sent:
amount,currency,interval, andservicebecome optional and are resolved from the catalog- Each item stores a price snapshot used for billing even if the catalog price changes later
Examples
Request
curl --request POST \
--url 'https://sandbox.ecartpay.com/api/subscriptions' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN' \
--header 'content-type: application/json' \
--data '{
"customer_id": "68cdcfa92ebbd864ef059453",
"trial_period_days": 0,
"items": [
{
"product_id": "68a4c3150b28a9584305a2a6",
"price_id": "68f1a2b3c4d5e6f7a8b9c0d1"
},
{
"product_id": "68b1d2e3f4a5b6c7d8e9f001",
"price_id": "68f2b3c4d5e6f7a8b9c0d2"
}
]
}'Response
{
"id": "68f4d5e6f7a8b9c0d3e4f5",
"account_id": "68a4c3150b28a9584305a2a6",
"customer_id": "68cdcfa92ebbd864ef059453",
"status": "active",
"service": "Platform Access",
"amount": 499,
"currency": "MXN",
"interval": "monthly",
"frequency": 1,
"trial_period_days": 0,
"items": [
{
"product_id": "68a4c3150b28a9584305a2a6",
"price_id": "68f1a2b3c4d5e6f7a8b9c0d1",
"quantity": 1,
"name": "Platform Access",
"metered": false,
"price_snapshot": {
"unit_amount": 499,
"currency": "MXN",
"pricing_model": "standard",
"billing_interval": "monthly"
}
},
{
"product_id": "68b1d2e3f4a5b6c7d8e9f001",
"price_id": "68f2b3c4d5e6f7a8b9c0d2",
"quantity": 1,
"name": "API Usage",
"unit_label": "transaction",
"metered": true,
"price_snapshot": {
"unit_amount": 0,
"currency": "MXN",
"pricing_model": "volume_minimum",
"metered_unit_label": "transaction",
"billing_interval": "monthly",
"pricing_model_config": {
"volume_tiers": [
{
"min_quantity": 1,
"max_quantity": 10000,
"unit_rate": 0.01,
"minimum_spend": 20
}
]
}
}
}
],
"created_at": "2026-06-17T18:05:00.000Z",
"updated_at": "2026-06-17T18:05:00.000Z"
}Checkout behavior for usage-only plans:
- If the subscription total is $0 because all items are usage-based, checkout validates the card instead of charging immediately
- Usage is reported during the billing period and charged on renewal together with any fixed base amount
Get Single Subscription
Advanced subscriptions return the full items[] array with stored price snapshots.
Visit our API Reference to test this endpoint.
Endpoint
GET https://ecartpay.com/api/subscriptions/:idGET https://sandbox.ecartpay.com/api/subscriptions/:id
Headers
Authorization: token
Path parameters
id— Subscription ID
Examples
Request
curl --request GET \
--url 'https://sandbox.ecartpay.com/api/subscriptions/68f4d5e6f7a8b9c0d3e4f5' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN'Response
{
"id": "68f4d5e6f7a8b9c0d3e4f5",
"status": "active",
"service": "Platform Access",
"amount": 499,
"currency": "MXN",
"interval": "monthly",
"frequency": 1,
"last_payment_date": "2026-06-17T18:10:00.000Z",
"next_payment_date": "2026-07-17T18:10:00.000Z",
"items": [
{
"product_id": "68a4c3150b28a9584305a2a6",
"price_id": "68f1a2b3c4d5e6f7a8b9c0d1",
"quantity": 1,
"name": "Platform Access",
"metered": false,
"price_snapshot": {
"unit_amount": 499,
"currency": "MXN",
"pricing_model": "standard",
"billing_interval": "monthly"
}
},
{
"product_id": "68b1d2e3f4a5b6c7d8e9f001",
"price_id": "68f2b3c4d5e6f7a8b9c0d2",
"quantity": 1,
"name": "API Usage",
"metered": true,
"price_snapshot": {
"pricing_model": "volume_minimum",
"pricing_model_config": {
"volume_tiers": [
{
"min_quantity": 1,
"max_quantity": 10000,
"unit_rate": 0.01,
"minimum_spend": 20
}
]
}
}
}
]
}Report Usage
Report customer consumption for metered catalog items. Pending usage is billed on the next renewal.
Visit our API Reference to create a usage record.
Endpoint
POST https://ecartpay.com/api/subscriptions/:id/usage_recordsPOST https://sandbox.ecartpay.com/api/subscriptions/:id/usage_records
Headers
Authorization: tokenContent-Type: application/json
Path parameters
id— Subscription ID
Body
| Field | Required | Description |
|---|---|---|
quantity | Yes | Positive usage amount to add |
idempotency_key | Yes | Unique key per subscription (safe retries) |
price_id | Conditional | Required when the subscription has multiple metered items |
recorded_at | No | ISO timestamp; defaults to now |
Examples
Request — single metered item
curl --request POST \
--url 'https://sandbox.ecartpay.com/api/subscriptions/68f4d5e6f7a8b9c0d3e4f5/usage_records' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN' \
--header 'content-type: application/json' \
--data '{
"quantity": 2500,
"idempotency_key": "usage-event-2026-06-17-001"
}'Request — multiple metered items
When a subscription includes more than one usage-based product, send price_id on every usage record:
curl --request POST \
--url 'https://sandbox.ecartpay.com/api/subscriptions/68f4d5e6f7a8b9c0d3e4f5/usage_records' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN' \
--header 'content-type: application/json' \
--data '{
"price_id": "68f2b3c4d5e6f7a8b9c0d2",
"quantity": 2500,
"idempotency_key": "api-usage-2026-06-17-001"
}'curl --request POST \
--url 'https://sandbox.ecartpay.com/api/subscriptions/68f4d5e6f7a8b9c0d3e4f5/usage_records' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN' \
--header 'content-type: application/json' \
--data '{
"price_id": "68f5c6d7e8f9a0b1c2d3e4f6",
"quantity": 120,
"idempotency_key": "sms-usage-2026-06-17-001"
}'Response
{
"id": "68f6d7e8f9a0b1c2d3e4f5a6",
"price_id": "68f2b3c4d5e6f7a8b9c0d2",
"name": "API Usage",
"unit_label": "transaction",
"quantity": 2500,
"amount": 25,
"idempotency_key": "api-usage-2026-06-17-001",
"recorded_at": "2026-06-17T18:30:00.000Z",
"created_at": "2026-06-17T18:30:00.000Z",
"billed_at": null,
"order_id": null,
"billing_status": "pending"
}Idempotency:
- Re-sending the same
idempotency_keyfor the same subscription returns the existing record instead of creating a duplicate
ImportantUsage records can only be created on active subscriptions that contain at least one metered catalog item.
Get Usage Summary
Returns pending and billed usage for the current billing period, broken down per metered item.
Visit our API Reference to get usage summary.
Endpoint
GET https://ecartpay.com/api/subscriptions/:id/usage_records/summaryGET https://sandbox.ecartpay.com/api/subscriptions/:id/usage_records/summary
Headers
Authorization: token
Path parameters
id— Subscription ID
Examples
Request
curl --request GET \
--url 'https://sandbox.ecartpay.com/api/subscriptions/68f4d5e6f7a8b9c0d3e4f5/usage_records/summary' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN'Response
{
"pending_quantity": 2500,
"pending_amount": 25,
"metered_unit_amount": 0.01,
"metered_unit_label": "transaction",
"total_records": 3,
"pending_records_count": 2,
"paid_records_count": 1,
"paid_quantity": 1000,
"paid_amount": 20,
"current_period_start": "2026-06-17T18:10:00.000Z",
"current_period_end": "2026-07-17T18:10:00.000Z",
"items": [
{
"price_id": "68f2b3c4d5e6f7a8b9c0d2",
"product_id": "68b1d2e3f4a5b6c7d8e9f001",
"name": "API Usage",
"unit_label": "transaction",
"metered_unit_amount": 0.01,
"metered_unit_label": "transaction",
"pricing_model": "volume_minimum",
"pending_quantity": 2500,
"pending_amount": 25,
"paid_quantity": 1000,
"paid_amount": 20,
"billing_snapshot": {
"pricing_model": "volume_minimum",
"total_quantity": 2500,
"unit_rate": 0.01,
"minimum_spend": 20,
"calculated_cost": 25,
"final_invoice_amount": 25,
"volume_tier_index": 0
}
}
]
}Volume minimum example:
If calculated_cost is below minimum_spend, renewal uses the minimum:
{
"billing_snapshot": {
"pricing_model": "volume_minimum",
"total_quantity": 500,
"unit_rate": 0.01,
"minimum_spend": 20,
"calculated_cost": 5,
"final_invoice_amount": 20,
"volume_tier_index": 0
}
}List Usage Records
Paginate individual usage events for auditing and reconciliation.
Visit our API Reference to list usage records.
Endpoint
GET https://ecartpay.com/api/subscriptions/:id/usage_recordsGET https://sandbox.ecartpay.com/api/subscriptions/:id/usage_records
Headers
Authorization: token
Path parameters
id— Subscription ID
Query parameters
page— Page numberlimit— Page size (max250)billing_status—all,pending, orpaidperiod—current(default) orall
Examples
Request
curl --request GET \
--url 'https://sandbox.ecartpay.com/api/subscriptions/68f4d5e6f7a8b9c0d3e4f5/usage_records?billing_status=pending&period=current&page=1&limit=50' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN'Response
{
"count": 2,
"pages": 1,
"docs": [
{
"id": "68f6d7e8f9a0b1c2d3e4f5a6",
"price_id": "68f2b3c4d5e6f7a8b9c0d2",
"name": "API Usage",
"unit_label": "transaction",
"quantity": 1500,
"amount": 15,
"idempotency_key": "api-usage-2026-06-17-001",
"recorded_at": "2026-06-17T18:30:00.000Z",
"created_at": "2026-06-17T18:30:00.000Z",
"billed_at": null,
"order_id": null,
"billing_status": "pending"
},
{
"id": "68f7e8f9a0b1c2d3e4f5a6b7",
"price_id": "68f2b3c4d5e6f7a8b9c0d2",
"name": "API Usage",
"unit_label": "transaction",
"quantity": 1000,
"amount": 10,
"idempotency_key": "api-usage-2026-06-17-002",
"recorded_at": "2026-06-17T19:00:00.000Z",
"created_at": "2026-06-17T19:00:00.000Z",
"billed_at": null,
"order_id": null,
"billing_status": "pending"
}
]
}Customer Usage Summary
Customers can read the same usage summary from the customer portal scope.
Endpoint
GET https://ecartpay.com/api/subscriptions/from-customer/:id/usage_records/summaryGET https://sandbox.ecartpay.com/api/subscriptions/from-customer/:id/usage_records/summary
Headers
Authorization: token
Path parameters
id— Subscription ID
Examples
Request
curl --request GET \
--url 'https://sandbox.ecartpay.com/api/subscriptions/from-customer/68f4d5e6f7a8b9c0d3e4f5/usage_records/summary' \
--header 'accept: application/json' \
--header 'authorization: sha512-YOUR_TOKEN'Response
Same structure as Get Usage Summary.
Renewal Billing Logic
At each renewal, EcartPay calculates:
total_renewal_amount = fixed_base_amount + usage_charge
Where:
- fixed_base_amount — Sum of non-metered catalog item amounts (plus any legacy subscription
amountbehavior) - usage_charge — Sum of pending usage per metered item in the current billing period
Standard usage pricing
usage_charge = total_period_quantity × metered_unit_amount
Volume minimum pricing
calculated_cost = total_period_quantity × tier.unit_rate
usage_charge = MAX(calculated_cost, tier.minimum_spend)
Billing period rules:
- Usage records are aggregated per
price_idwithin the current billing period - Pending records are marked as billed when the renewal order is paid
- Each billed order can store
usage_billing_snapshotsfor activity and reporting
Example renewal breakdown
Subscription with:
- Fixed platform fee:
$499 MXN - API usage:
2,500 transactionson avolume_minimumtier withunit_rate = 0.01,minimum_spend = 20
{
"base_amount": 499,
"usage_quantity": 2500,
"usage_charge": 25,
"total_amount": 524
}If usage were only 500 transactions:
{
"base_amount": 499,
"usage_quantity": 500,
"usage_charge": 20,
"total_amount": 519
}Business Rules and Validation
Catalog item rules
- Only recurring prices can be attached to subscription items
- All items on one subscription must share the same billing interval
price_idmust belong to the providedproduct_id- All items must use the same currency
quantitymust be1when provided
Pricing model rules
- Non-metered items only support
pricing_model: "standard" - Metered items support
standardorvolume_minimum volume_minimumrequiresmetered: trueand at least one volume tier
Usage reporting rules
- Subscription must be
active - At least one catalog item must be metered
- One metered item →
price_idis optional - Multiple metered items →
price_idis required on every usage record idempotency_keymust be unique per subscription
Recommended integration flow
- Create catalog products and recurring prices
- Create a subscription template or subscription with
items[] - Customer completes checkout and adds a payment method
- Report usage throughout the billing period with idempotent events
- Monitor pending usage via
GET /usage_records/summary - On renewal, EcartPay charges fixed amount + pending usage automatically