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
⚠️

IMPORTANT

To follow the steps below, you must have a valid Authorization Token. For more information, refer to: Authorization Token


Overview

Standard vs advanced

Standard subscriptionAdvanced subscription
PricingSingle amount + serviceOne or more catalog items[]
Usage billingNot supportedSupported via usage_records
Amount at creationRequiredDerived from catalog prices (can be 0 for usage-only plans)
IntervalSet in requestDerived from catalog prices (all items must share the same interval)
Price snapshotN/AStored on each item at creation time

Supported pricing models on catalog prices

pricing_modelMetered requiredBilling behavior
standardNoFixed recurring charge from unit_amount
standardYesUsage charge = quantity × metered_unit_amount
volume_minimumYesUsage charge = MAX(total_quantity × tier.unit_rate, tier.minimum_spend)
📘

Note

volume_minimum always requires metered: true and a pricing_model_config.volume_tiers array 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/prices
  • POST https://sandbox.ecartpay.com/api/products/:product_id/prices

Headers

  • Authorization: token
  • Content-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-template
  • POST https://sandbox.ecartpay.com/api/subscriptions-template

Headers

  • Authorization: token
  • Content-Type: application/json

Body

  • frequency — Billing frequency multiplier (required)
  • items — Catalog line items (see structure below)
  • trial_period_days — Optional trial period
  • billing_cycle — Optional fixed billing day/month
  • benefits — Optional list of plan benefits
  • merchant_management — Optional checkout management flag
  • redirect_url — Required when merchant_management is true

items[] structure

FieldRequiredDescription
product_idYesCatalog product ID
price_idYesRecurring product price ID
quantityNoMust be 1 when provided
nameNoOptional snapshot override
skuNoOptional snapshot override
unit_labelNoOptional snapshot override
❗️

Important

All items must use recurring prices with the same billing interval. Mixing monthly and yearly prices 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/subscriptions
  • POST https://sandbox.ecartpay.com/api/subscriptions

Headers

  • Authorization: token
  • Content-Type: application/json

Body

  • customer_id — Required customer ID
  • template_id — Optional template ID (alternative to manual items[])
  • items — Optional catalog line items
  • card_ids — Optional payment methods (1–5)
  • trial_period_days — Optional trial period
  • billing_cycle — Optional billing anchor
  • benefits — Optional benefit list

When items[] is sent:

  • amount, currency, interval, and service become 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/:id
  • GET 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_records
  • POST https://sandbox.ecartpay.com/api/subscriptions/:id/usage_records

Headers

  • Authorization: token
  • Content-Type: application/json

Path parameters

  • id — Subscription ID

Body

FieldRequiredDescription
quantityYesPositive usage amount to add
idempotency_keyYesUnique key per subscription (safe retries)
price_idConditionalRequired when the subscription has multiple metered items
recorded_atNoISO 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_key for the same subscription returns the existing record instead of creating a duplicate
❗️

Important

Usage 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/summary
  • GET 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_records
  • GET https://sandbox.ecartpay.com/api/subscriptions/:id/usage_records

Headers

  • Authorization: token

Path parameters

  • id — Subscription ID

Query parameters

  • page — Page number
  • limit — Page size (max 250)
  • billing_statusall, pending, or paid
  • periodcurrent (default) or all

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/summary
  • GET 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 amount behavior)
  • 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:

  1. Usage records are aggregated per price_id within the current billing period
  2. Pending records are marked as billed when the renewal order is paid
  3. Each billed order can store usage_billing_snapshots for activity and reporting

Example renewal breakdown

Subscription with:

  • Fixed platform fee: $499 MXN
  • API usage: 2,500 transactions on a volume_minimum tier with unit_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_id must belong to the provided product_id
  • All items must use the same currency
  • quantity must be 1 when provided

Pricing model rules

  • Non-metered items only support pricing_model: "standard"
  • Metered items support standard or volume_minimum
  • volume_minimum requires metered: true and at least one volume tier

Usage reporting rules

  • Subscription must be active
  • At least one catalog item must be metered
  • One metered item → price_id is optional
  • Multiple metered items → price_id is required on every usage record
  • idempotency_key must be unique per subscription

Recommended integration flow

  1. Create catalog products and recurring prices
  2. Create a subscription template or subscription with items[]
  3. Customer completes checkout and adds a payment method
  4. Report usage throughout the billing period with idempotent events
  5. Monitor pending usage via GET /usage_records/summary
  6. On renewal, EcartPay charges fixed amount + pending usage automatically

Related Documentation