Overview

The Simple API is the latest version of Zuora API with a simple object model. It is available to all Zuora customers in Sandbox environments.

The Simple API is strongly recommended for all new integrations. In a nutshell:

  • If you have not built integrations with Zuora yet, start with the Simple API.
  • If you have integrated or started integrating with Zuora, you can continue to use the v1 API but can evaluate whether Simple API fits your needs then determine whether you need an upgrade.
  • If you have not built integrations with Zuora but have specific use cases that you do not find in this Simple API Guides, reach out to your Zuora representatives or submit a request at Zuora Global Support for consultation.

This set of guides walks you through:

  • Common Simple API use cases and code examples using Java client library (also known as SDK) and cURL
  • Reference documentation for query parameters and error handling of Simple API

Visit the Zuora Developers Community to report issues or discuss the Zuora Java SDK.

The following features are required for Zuora Java SDK:

  • The Orders feature. If this feature is enabled in your tenant, you can see Orders under Customers in the left navigation panel in the Zuora UI. To obtain access to this feature, submit a request at Zuora Global Support.
  • The Invoice Settlement feature. If this feature is enabled in your tenant, you can see Credit and Debit Memos under Billing in the left navigation panel in the Zuora UI. To obtain access to this feature, submit a request at Zuora Global Support.

In addition, the use cases in this guide assume that:

Introduction to Zuora objects

Zuora objects

Everything in your Zuora tenant is an object, whether you create it with the API or not. The price you define for a product plan corresponds to a Price object, you track customers with Account objects, you store your customer’s payment details in Payment Method objects, and so on.

Even low-code and no-code integrations produce these objects. So do the actions you perform in the UI. For instance, when you manually create a customer account in Zuora Central, it still creates an Account object.

Integration is made out of cooperating objects

To track customers, manage subscriptions and accept recurring payments, a system needs to create several objects and manage them through several states.

Your Zuora integration is a system that handles this creation and management by communicating with Zuora.

Objects have lives

The API uses a single object to track each process. You create the object at the start of the process, and after every step you can check its state and see when it transitioned from its previous state to the current one.

For instance, when an invoice is posted, it will transition from a draft to an open state; when it has been paid, it will transition from an open to a paid state. The date and time on which the invoice was created will be recorded on the object in the created_time field and the date and time on which it was posted will be recorded in the state_transitions.posted_time field.

 


 

Create products and prices

Products describe the goods or services you offer to your customers. Each product has a unique id and SKU.

Plans are collections of prices. While products help you track inventory or provisioning, plans and prices help you track payment terms.

Prices determine how you charge your customers for the product they subscribe to. Since products allow you to track inventory and provisioning you can change prices without having to change your provisioning scheme.

Different physical goods or levels of service are represented by products, and pricing and billing cycle options are represented by prices grouped together in a plan. For example, you offer a single ”Gold” product, and it has two plans – monthly plan and yearly plan. Each plan has a price for $100 for the monthly plan, and $1000 year for the yearly plan.

You can easily create prices without explicitly specifying the type of the price. Based on the fields you specified, the type of the price is automatically identified and determined. For example, if you want to create per-unit prices, you only need to specify the following required fields, then Zuora will automatically create a per-unit price for you:

  • unit_of_measure
  • unit_amounts

In another example, if you want to create a tiered price that charges your customers based on the product volume, the required fields you should specify only include:

  • unit_of_measure
  • quantity
  • tiers
  • tiers_mode

Create flat fee prices

Flat fee overview

Many businesses offer their customers a choice of service options, a model called good-better-best. If you want to offer three different service levels: Basic, Growth, and Enterprise, and offer a monthly or a yearly price for each service level. The following table is what that would look like on Zuora:

Basic Growth Enterprise
$10/mo. or $100/yr. $20/mo. or $200/yr. $75/mo. or $850/yr.

For these products, we can break down them as follows:

Product Product Product
Basic Growth Enterprise
Plan 1 Plan 1 Plan 1
Basic Monthly Growth Monthly Enterprise Monthly
Price 1 Price 1 Price 1
$10 monthly $20 monthly $75 monthly
Plan 2 Plan 2 Plan 2
Basic Yearly Growth Yearly Enterprise Yearly
Price 2 Price 2 Price 2
$100 yearly $220 yearly $850 yearly

The following code examples show how to create a good-better-best model on Zuora for the Basic product and its plans and prices. You can reference the following code samples and create products, plans, and prices for Growth and Enterprise products.

  1. Create a Basic product for the Basic service level.
  2. Create a Basic Monthly plan for the Basic product.
  3. Create a Basic Monthly Fee price for the Basic Monthly plan.
  4. Create a Basic Yearly plan for the Basic product.
  5. Create a Basic Yearly Fee price for the Basic Yearly plan.
// 1. Create the Basic Product
curl -X POST "https://rest.sandbox.na.zuora.com/v2/products"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{ 
    "name": "Basic",
    "description": "Basic Product", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

// 2. Create the Basic Monthly Plan
curl -X POST "https://rest.sandbox.na.zuora.com/v2/plans"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Basic Monthly",
    "product_id": "2c94a116ef504f65b5ef1e9e9e8377e1",
    "description": "Monthly plan of the Basic product", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

// 3. Create monthly price for Basic Monthly plan
curl -X POST "https://rest.sandbox.na.zuora.com/v2/prices"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Basic Monthly Fee",
    "plan_id": "2c921528ef504f65b5ef1e9e9e8362f2",
    "description": "Monthly fee of the Basic Monthly plan", 
    "amounts": {
        "USD": 10
    },
    "recurring": {
        "recurring_on": "account_cycle_date",
        "interval": "month",
        "interval_count": 1,
        "timing": "in_advance"
    },
    "start_event": "contract_effective", 
    "price_base_interval": "billing_period",
    "deferred_revenue_accounting_code": "Credit Card",
    "recognized_revenue_accounting_code": "Credit Card"
}' 

//4. Create Basic Yearly plan
curl -X POST "https://rest.sandbox.na.zuora.com/v2/plans"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Basic Yearly",
    "product_id": "2c94a116ef504f65b5ef1e9e9e8377e1",
    "description": "Yearly plan of the Basic product", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

//5. Create price for Basic Yearly plan

curl -X POST "https://rest.sandbox.na.zuora.com/v2/prices"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Basic Yearly Fee",
    "plan_id": "8ad08aef81375b10018137f8659d4e1e",
    "description": "Yearly fee of the Basic Yearly plan", 
    "amounts": {
        "USD": 100
    },
    "recurring": {
        "recurring_on": "account_cycle_date",
        "interval": "year",
        "interval_count":1,
        "timing": "in_advance"
    },
    "start_event": "contract_effective", 
    "price_base_interval": "billing_period",
    "deferred_revenue_accounting_code": "Subscription Revenue",
    "recognized_revenue_accounting_code": "Subscription Revenue"
}' 
//1. Create the Basic product
LocalDate startDate = LocalDate.of(2022, 4, 1);
LocalDate endDate = LocalDate.of(2032, 4, 1);

ProductCreateRequest productRequest = new ProductCreateRequest()
    .name('Basic')
    .startDate(startDate)
    .endDate(endDate)
    .description('Basic Product');

Product basicProduct = zuoraClient.products().createProduct(productRequest);

//2. Create the Basic Monthly plan
PlanCreateRequest monthlyPlanRequest = new PlanCreateRequest()
    .name('Basic Monthly')
    .productId(basicProduct.getId())
    .startDate(startDate)
    .endDate(endDate)
    .description('Monthly plan of the Basic product')
          
Plan basicMonthlyPlan = zuoraClient.plans().createPlan(monthlyPlanRequest);

//3. Create price for Basic Monthly Plan
Map<String, BigDecimal> monthlyAmounts = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("10.0"));
}};

PriceCreateRequest monthlyPriceRequest = new PriceCreateRequest()
    .amounts(monthlyAmounts)
    .name("Basic Monthly Fee")
    .priceBaseInterval(PriceBaseIntervalEnum.BILLING_PERIOD)
    .planId(basicMonthlyPlan.getId())
    .description("Monthly fee of the Basic Monthly plan")
    .recurring(new Recurring()
        .recurringOn(Recurring.RecurringOnEnum.ACCOUNT_CYCLE_DATE)
        .intervalCount(1)
        .interval(IntervalEnum.MONTH)
        .timing(TimingEnum.ADVANCE)
    )
    .startEvent(StartEventEnum.CONTRACT_EFFECTIVE)
    .deferredRevenueAccountingCode("Subscription Revenue")
    .recognizedRevenueAccountingCode("Subscription Revenue");

Price baseMonthlyPrice = zuoraClient.prices().createPrice(monthlyPriceRequest);

// 4. Create the Basic Yearly plan
PlanCreateRequest yearlyPlanRequest = new PlanCreateRequest()
    .name('Basic Yearly')
    .productId(basicProduct.getId())
    .startDate('2022-04-01')
    .endDate('2032-04-01')
    .description('Yearly plan of the Basic product');
          
Plan basicYearlyPlan = zuoraClient.plans().createPlan(yearlyPlanRequest);

//5. Create the price for Basic Yearly plan

Map<String, BigDecimal> yearlyAmounts = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal(100.0));
}};

PriceCreateRequest yearlyPriceRequest = new PriceCreateRequest()
    .amounts(yearlyAmounts)
    .name("Basic Yearly Fee")
    .priceBaseInterval(PriceBaseIntervalEnum.BILLING_PERIOD)
    .planId(basicYearlyPlan.getId())
    .description("Yearly fee of the Basic Yearly plan")
    .recurring(new Recurring()
        .on(OnEnum.ACCOUNT_CYCLE_DATE)
        .intervalCount(1)
        .interval(IntervalEnum.YEAR)
        .timing(TimingEnum.ADVANCE)
    )
    .startEvent(StartEventEnum.CONTRACT_EFFECTIVE)
    .deferredRevenueAccountingCode("Subscription Revenue")
    .recognizedRevenueAccountingCode("Subscription Revenue");

Price baseYearlyPrice = zuoraClient.prices().postPrice(yearlyPriceRequest);


If the request succeeds, the returned response is as follows:

{
	"id": "8ad095b8816cd2650181805a74b22d90",
	"updated_by_id": "2c92c0946a6dffc0016a7faab604299b",
	"updated_time": "2022-06-20T02:03:40-07:00",
	"created_by_id": "2c92c0946a6dffc0016a7faab604299b",
	"created_time": "2022-06-20T02:03:40-07:00",
	"custom_fields": {
            "ChargeType__c": "Base"
	},
	"name": "Basic Monthly Fee",
	"description": "Monthly fee of the Basic Monthly plan",
	"recurring": {
		"recurring_on": "account_cycle_date",
		"usage": false,
		"interval": "month",
                "interval_count": 1,
		"timing": "in_advance"
	},
	"start_event": "contract_effective",
	"tax_code": "",
	"tax_inclusive": false,
	"unit_of_measure": "",
	"quantity": 1,
	"min_quantity": 0,
	"max_quantity": 0,
	"amounts": {
	    "USD": 20
	},
	"price_base_interval": "billing_period",
	"plan_id": "8ad08aef813e577201814402f18241e2",
	"charge_type": "Recurring",
	"charge_model": "Flat Fee Pricing"
}

Create per-unit prices

For per-unit prices, the amount to charge is expressed as a price per unit. The price is calculated based on the quantity of a service or product purchased by the customer, where the total price charged per period would be the quantity multiplied by the per-unit price. An example of a per unit charge would be a software-as-a-service vendor that charges $50 per user per month for their service.

Suppose that you are offering the following product and price:

  • Product: SaaS Service
  • Plan: SaaS Service Monthly plan
  • Price: $20 per unit per month

Before creating the corresponding price, ensure that you have configured the unit of measure in your Zuora tenant. In this scenario, you can set up user or license as the unit of measure. See Customize Units of Measure for more information.

To create a per unit pricing model lie this on Zuora using the Products, Plans and Prices APIs:

  1. Create the per unit product
  2. Create the per unit monthly plan
  3. Create a price for the monthly plan
  4. When you create subscriptions, specify a quantity to charge for each unit.
//1. Create the product

curl -X POST "https://rest.sandbox.na.zuora.com/v2/products"
     -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
     -H "Content-Type: application/json" 
     -d '{ 
              "name": "SaaS service",
              "description": "SaaS service charged on active users", 
              "start_date": "2022-06-01", 
              "end_date": "2032-06-01",
      }' 

//2. Create the per unit plan

curl -X POST "https://rest.sandbox.na.zuora.com/v2/plans"
     -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
     -H "Content-Type: application/json" 
     -d '{
            "name": "SaaS Service Monthly Plan",
            "product_id": "2c94a116ef504f65b5ef1e9e9e8377e1",  
            "description": "Monthly plan of the SaaS service", 
            "start_date": "2022-06-01", 
            "end_date": "2032-06-01"
          }' 

// 3. Create price for monthly plan
curl -X POST "https://rest.sandbox.na.zuora.com/v2/prices"
     -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
     -H "Content-Type: application/json" 
     -d '{
          "name": "Monthly Per Unit Price",
          "unit_of_measure": "License",
          "unit_amounts": {
            "USD": 20
          },
          "recurring": {
            "interval": "month",
            "recurring_on": "account_cycle_date",
            "interval_count": "1",
            "timing": "in_advance"
          },
          "plan_id": "2c921528ef504f65b5ef1e9e9e8362f2",
          "description": "Monthly per unit price", 
          "start_event": "contract_effective", 
          "price_base_interval": "month",
          "quantity": 10,
          "recognized_revenue_accounting_code": "Service Revenue",
          "deferred_revenue_accounting_code": "Service Revenue" 
        }' 

//4. Create a subscription
curl -X POST "https://rest.sandbox.na.zuora.com/v2/subscriptions"
     -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
     -H "Content-Type: application/json" 
     -d '{ 
    "account_data":{
         "bill_to": {
             "first_name": "Amy",
             "last_name": "Lawrence",
             "email": "amy.lawrence@zuora.com",
	"address":{
		"line1": "123 ABC Street",
"city": "San Francisco",
		 "state": "California",
 "country": "US"
	},
           "name": "Amy Lawrence account",
           "currency": "USD"
           },
        "subscription_plans": [{
            "plan_id": "8ad095b8813772670181383d05136860",
            "prices": [{
                 "price_id": "8ad0877b81375b220181388c877428f9",
                 "quantity": 20        
	}]
        }]
       }' 
LocalDate startDate = LocalDate.of(2022, 4, 1);
LocalDate endDate = LocalDate.of(2032, 4, 1);

//1. Create the product

ProductCreateRequest productRequest = new ProductCreateRequest()
      .name('SaaS service')
      .startDate(startDate)
      .endDate(endDate)
      .description('SaaS service charged on active users');
          
Product newProduct = zuoraClient.products().createProduct(productRequest); 

//2. Create the per unit plan

PlanCreateRequest planRequest = new PlanCreateRequest()
      .name('SaaS Service Monthly Plan')
      .productId(newProduct.getId())
      .startDate(startDate)
      .endDate(endDate)
      .description('Monthly plan of the SaaS Service')
          
Plan newPlan = zuoraClient.plans().createPlan(planRequest);


// 3. Create price for monthly plan

Map<String, BigDecimal> unitAmount = new HashMap<String, BigDecimal>().put("USD", new BigDecimal("20.00"));
          
PriceCreateRequest priceRequest = new PriceCreateRequest()
      .unitAmounts(unitAmount)
      .unitOfMeasure("License")
      .name("Monthly Per Unit Price")
      .priceBaseInterval(PriceBaseIntervalEnum.MONTH)
      .planId(newPlan.getId())
      .description("Monthly per unit price")
      .recurring(new Recurring()
          .interval(IntervalEnum.MONTH)
          .intervalCount(1)
          .timing(TimingEnum.ADVANCE)
          .recurringOn(Recurring.RecurringOnEnum.ACCOUNT_CYCLE_DATE)
      )
      .quantity(new BigDecimal("10"))
      .startEvent(StartEventEnum.CONTRACT_EFFECTIVE)
      .recognizedRevenueAccountingCode("Subscription Revenue")
      .deferredRevenueAccountingCode("Subscription Revenue");

Price newPrice = zuoraClient.prices().createPrice(priceRequest);


//4. Create a subscription

LocalDate todayDate = LocalDate.now();
AccountContactCreateRequest contactCreateRequest = new AccountContactCreateRequest()
    .firstName("Amy")
    .lastName("Lawrence")
    .address(new Address()
        .line1("123 ABC Street")
        .city("San Francisco")
        .state("CA")
        .country("US"));
            
AccountCreateRequest accountCreateRequest = new AccountCreateRequest()
        .name("Amy Lawrence account")
        .billTo(contactCreateRequest)
        .currency("USD");

SubscriptionItemCreateRequest newItem = new SubscriptionItemCreateRequest()
	.priceId(newPrice.getId())
	.quantity(new BigDecimal("20"));

SubscriptionCreateRequest subscriptionCreateRequest = new SubscriptionCreateRequest()
    .accountData(accountCreateRequest)
    .subscriptionPlans(Collections.singletonList(new SubscriptionPlanCreateRequest()
        .planId(plan.getId())
        .prices(Collections.singletonList(subscriptionItemCreateRequest))))
    .processingOptions(new ProcessingOptions()
        .collectionMethod(CollectionMethodEnum.CREATE_INVOICE)
        .documentDate(todayDate.plusMonths(2)))
    .startOn(new StartOn()
        .contractEffective(todayDate)
        .customerAcceptance(todayDate)
        .serviceActivation(todayDate));
       
Subscription subscription = zuoraClient.subscriptions().createSubscription(subRequest);

Create tiered prices - volume

Prices can represent tiers, allowing the unit cost to change with quantity or usage. You might, for example, want to offer lower rates for customers who use more units per month. The following examples show two different ways to adjust pricing as usage increases: volume-based pricing and graduated pricing.

Use tiers if you need non-linear pricing when quantity or usage changes. You can also combine tiered pricing with base fees to create more complex pricing models.

When you create a price with tiers, the unit cost varies depending on how many units your customer buys. Here’s an example:-

Tier Unit cost
1-5 (up_to=5) $5 (unit_amount=5)
6-10 (up_to=10) $4 (unit_amount=4)
11-15 (up_to=15) $3 (unit_amount=3)
16-20 (up_to=20) $2 (unit_amount=2)
21-1000 (up_to=1000) $1 (unit_amount=1)

With volume pricing the subscription item is billed at the tier corresponding to the amount of usage at the end of the billing period. To use volume-based tiering, set volume as the value of tiers_mode.

A customer with anywhere from 0-5 licenses will be charged a per unit price of 5 USD at the end of the period (e.g. 5 units x $5 per unit = $25). However, if they purchase 6 licenses the following month, they will be charged a per unit price of 4 USD (6 units x $4 per unit = $24).

Quantity/Usage at end of period Total cost
1 $5
5 $25
6 $24
20 $40
25 $25

Because the tier price applies to the entire quantity or usage, the total can decrease when calculating the final cost.

// 1. Create a product

curl -X POST "https://rest.sandbox.na.zuora.com/v2/products"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{ 
    "name": "Product with volume price",
    "description": "Product with a volume price", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

//2. Create a plan

curl -X POST "https://rest.sandbox.na.zuora.com/v2/plans"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Plan with volume price",
    "product_id": "2c94a116ef504f65b5ef1e9e9e8377e1",
    "description": "Plan with a volume price", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'


//3. Create a price

curl -X POST "https://rest.sandbox.na.zuora.com/v2/prices"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Volume Price",
    "plan_id": "2c921528ef504f65b5ef1e9e9e8362f2",
    "description": "Price in volume mode", 
    "tiers_mode": "volume",
    "unit_of_measure": "License",
    "quantity": 1,
    "tiers": [
        {
            "up_to": 5,
            "unit_amounts": {
                "USD": 5
            }
        },
        {
            "up_to": 10,
            "unit_amounts": {
                "USD": 4
            }
        },
        {
            "up_to": 15,
            "unit_amounts": {
                "USD": 3
            }
        },
        {
            "up_to": 20,
            "unit_amounts": {
                "USD": 2
            }
        },
        {
            "up_to": 1000,
            "unit_amounts": {
                "USD": 1
            }
        }
    ],
    "start_event": "contract_effective", 
    "price_base_interval": "billing_period",
    "deferred_revenue_accounting_code": "Credit Card",
    "recognized_revenue_accounting_code": "Credit Card"
}' 
LocalDate startDate = LocalDate.of(2022, 4, 1);
LocalDate endDate = LocalDate.of(2032, 4, 1);

// 1. Create a product

ProductCreateRequest productRequest = new ProductCreateRequest()
    .name('Product with volume price')
    .startDate(startDate)
    .endDate(endDate)
    .description('Product with a volume price');

Product productWithVolumePrice = zuoraClient.products().createProduct(productRequest);

//2. Create a plan

PlanCreateRequest planRequest = new PlanCreateRequest()
    .name('Plan with volume price')
    .productId(productWithVolumePrice.getId())
    .startDate(startDate)
    .endDate(endDate)
    .description('Plan with a volume price');
          
Plan planWithVolumePrice = zuoraClient.plans().createPlan(planRequest);


//3. Create a price

Map<String, BigDecimal> unitAmounts1 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("5"));
}};
Tier tier1 = new Tier()
    .upTo(new BigDecimal("5"))
    .unitAmounts(unitAmounts1);

Map<String, BigDecimal> unitAmounts2 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("4"));
}};
Tier tier2 = new Tier()
    .upTo(new BigDecimal("10"))
    .unitAmounts(unitAmounts2);

Map<String, BigDecimal> unitAmounts3 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("3"));
}};
Tier tier3 = new Tier()
    .upTo(new BigDecimal("15"))
    .unitAmounts(unitAmounts3);

Map<String, BigDecimal> unitAmounts4= new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("2"));
}};
Tier tier4 = new Tier()
    .upTo(new BigDecimal("20"))
    .unitAmounts(unitAmounts4);

Map<String, BigDecimal> unitAmounts5 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("1"));
}};
Tier tier5 = new Tier()
    .upTo(new BigDecimal("1000"))
    .unitAmounts(unitAmounts5);

List tiers = new ArrayList();
tiers.add(tier1);
tiers.add(tier2);
tiers.add(tier3);
tiers.add(tier4);
tiers.add(tier5);

PriceCreateRequest priceRequest = new PriceCreateRequest()
    .name("Volume Price")
    .planId(planWithVolumePrice.getId())
    .description("Price in volume mode")
    .tiersMode(TiersModeEnum.VOLUME)
    .unitOfMeasure("License")
    .quantity(new BigDecimal("1"))
    .tiers(tiers)
    .startEvent(StartEventEnum.CONTRACT_EFFECTIVE)
    .priceBaseInterval(PriceBaseIntervalEnum.BILLING_PERIOD)
    .deferredRevenueAccountingCode("Subscription Revenue")
    .recognizedRevenueAccountingCode("Subscription Revenue");

Price volumePrice = zuoraClient.prices().createPrice(priceRequest);

Create tiered prices - graduated

While similar to volume pricing, graduated pricing charges for the usage in each tier instead of applying a single price to all usage. To use graduated tiers, set the value of tiers_mode to graduated.

With graduated pricing, 5 units result in the same charge as volume-based pricing-25 USD at 5 USD per unit. This changes as usage breaks out of the first tier. A customer with more than 5 units is charged 5 USD per unit for the first 5 units, then 4 USD for units 6 through 10, 3 USD for units 11 through 20 and 2 USD thereafter. A customer with 6 units would be charged 29 USD, 25 USD for the first 5 units and 4 USD for the 6th unit. The graduated tiered pricing for such case is described as follows:

Tier Unit cost
1-5 $5
6-10 $4
11-20 $3
21-1000 $2

With this pricing, the total cost for different quantities are calculated as follows:

Quantity/Usage at end of period Total cost
1 $5 (1*$5)
5 $25 (5*$5)
6 $29 (5*$5+1*$4)
20 $75 (5*$5+5*$4+10*$3)
25 $85 (5*$5+5*$4+10*$3+5*$2)

See the following code samples for the implementation of this graduated tiered price:

// 1. Create a product

curl -X POST "https://rest.sandbox.na.zuora.com/v2/products"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{ 
    "name": "Product with graduated price",
    "description": "Product with a graduated price", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

//2. Create a plan

curl -X POST "https://rest.sandbox.na.zuora.com/v2/plans"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Plan with graduated price",
    "product_id": "2c94a116ef504f65b5ef1e9e9e8377e1",
    "description": "Plan with a graduated price", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

//3. Create a price

curl -X POST "https://rest.sandbox.na.zuora.com/v2/prices"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Graduated Price",
    "plan_id": "2c921528ef504f65b5ef1e9e9e8362f2",
    "description": "Price in graduated mode", 
    "tiers_mode": "graduated",
    "unit_of_measure": "License",
    "quantity": 1,
    "tiers": [
        {
            "up_to": 5,
            "unit_amounts": {
                "USD": 5
            }
        },
        {
            "up_to": 10,
            "unit_amounts": {
                "USD": 4
            }
        },
        {
            "up_to": 20,
            "unit_amounts": {
                "USD": 3
            }
        },
        {
            "up_to": 1000,
            "unit_amounts": {
                "USD": 2
            }
        }
    ],
    "start_event": "contract_effective", 
    "price_base_interval": "billing_period",
    "deferred_revenue_accounting_code": "Credit Card",
    "recognized_revenue_accounting_code": "Credit Card"
}' 
LocalDate startDate = LocalDate.of(2022, 4, 1);
LocalDate endDate = LocalDate.of(2032, 4, 1);

// 1. Create a product

ProductCreateRequest productRequest = new ProductCreateRequest()
    .name('Product with graduated price')
    .startDate(startDate)
    .endDate(endDate)
    .description('Product with a graduated price');

Product productWithGraduatedPrice = zuoraClient.products().createProduct(productRequest);

//2. Create a plan

PlanCreateRequest planRequest = new PlanCreateRequest()
    .name('Plan with graduated price')
    .productId(productWithGraduatedPrice.getId())
    .startDate(startDate)
    .endDate(endDate)
    .description('Plan with a graduated price');
          
Plan planWithGraduatedPrice = zuoraClient.plans().createPlan(planRequest);

//3. Create a price

Map<String, BigDecimal> unitAmounts1 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("5"));
}};
Tier tier1 = new Tier()
    .upTo(new BigDecimal("5"))
    .unitAmounts(unitAmounts1);

Map<String, BigDecimal> unitAmounts2 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("4"));
}};
Tier tier2 = new Tier()
    .upTo(new BigDecimal("10"))
    .unitAmounts(unitAmounts2);

Map<String, BigDecimal> unitAmounts3 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("3"));
}};
Tier tier3 = new Tier()
    .upTo(new BigDecimal("20"))
    .unitAmounts(unitAmounts3);

Map<String, BigDecimal> unitAmounts4= new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("2"));
}};
Tier tier4 = new Tier()
    .upTo(new BigDecimal("1000"))
    .unitAmounts(unitAmounts4);

List tiers = new ArrayList();
tiers.add(tier1);
tiers.add(tier2);
tiers.add(tier3);
tiers.add(tier4);

PriceCreateRequest priceRequest = new PriceCreateRequest()
    .name("Graduated Price")
    .planId(planWithGraduatedPrice.getId())
    .description("Price in graduated mode")
    .tiersMode(TiersModeEnum.GRADUATED)
    .unitOfMeasure("License")
    .quantity(new BigDecimal("1"))
    .tiers(tiers)
    .startEvent(StartEventEnum.CONTRACT_EFFECTIVE)
    .priceBaseInterval(PriceBaseIntervalEnum.BILLING_PERIOD)
    .deferredRevenueAccountingCode("Subscription Revenue")
    .recognizedRevenueAccountingCode("Subscription Revenue");

Price graduatedPrice = zuoraClient.prices().createPrice(priceRequest);

Create tiered flat fee prices

You can specify a flat fee (amount) to add to the amount you charge your customer. This works for both tiers_mode=volume and tiers_mode=graduated. For example, you can have a flat fee that increases when certain usage thresholds are met:

Tier Unit cost
1-5 (up_to=5) $10 (amount=10)
6-10 (up_to=10) $20 (amount=20)
11-15 (up_to=15) $30 (amount=30)
16-20 (up_to=20) $40 (amount=40)
21-1000 (up_to=1000) $50 (amount=50)

In this example, if quantity is 12 and tiers_mode=volume, the total amount to be billed is 30 USD.

If quantity is 12 and tiers_mode=graduated, the total amount is 10 USD + 20 USD + 30 USD = 60 USD. A tier must have either a unit_amount value or an amount value, but not both.

See the following code samples for the implementation for this price:

// 1. Create a product

curl -X POST "https://rest.sandbox.na.zuora.com/v2/products"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{ 
    "name": "Product with volume flat fees",
    "description": "Product with volume flat fees", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

//2. Create a plan

curl -X POST "https://rest.sandbox.na.zuora.com/v2/plans"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Plan with volume flat fees",
    "product_id": "2c94a116ef504f65b5ef1e9e9e8377e1",
    "description": "Plan with volume flat fees", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

//3. Create a price

curl -X POST "https://rest.sandbox.na.zuora.com/v2/prices"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Volume Flat Fee Price",
    "plan_id": "2c921528ef504f65b5ef1e9e9e8362f2",
    "description": "Price with volume flat fees", 
    "tiers_mode": "volume",
    "unit_of_measure": "License",
    "quantity": 1,
    "tiers": [
        {
            "up_to": 5,
            "amounts": {
                "USD": 10
            }
        },
        {
            "up_to": 10,
            "amounts": {
                "USD": 20
            }
        },
        {
            "up_to": 15,
            "amounts": {
                "USD": 30
            }
        },
        {
            "up_to": 20,
            "amounts": {
                "USD": 40
            }
        },
        {
            "up_to": 1000,
            "amounts": {
                "USD": 50
            }
        }
    ],
    "start_event": "contract_effective", 
    "price_base_interval": "billing_period",
    "deferred_revenue_accounting_code": "Credit Card",
    "recognized_revenue_accounting_code": "Credit Card"
}'  
LocalDate startDate = LocalDate.of(2022, 4, 1);
LocalDate endDate = LocalDate.of(2032, 4, 1);

// 1. Create a product
ProductCreateRequest productRequest = new ProductCreateRequest()
    .name('Product with volume flat fees')
    .startDate(startDate)
    .endDate(endDate)
    .description('Product with volume flat fees');

Product productWithVolumeFlatFees = zuoraClient.products().createProduct(productRequest);

//2. Create a plan

PlanCreateRequest planRequest = new PlanCreateRequest()
    .name('Plan with volume flat fees')
    .productId(productWithVolumeFlatFees.getId())
    .startDate(startDate)
    .endDate(endDate)
    .description('Plan with volume flat fees');
          
Plan planWithVolumeFlatFees = zuoraClient.plans().createPlan(planRequest);


//3. Create a price

Map<String, BigDecimal> amounts1 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("10"));
}};
Tier tier1 = new Tier()
    .upTo(new BigDecimal("5"))
    .amounts(amounts1);

Map<String, BigDecimal> amounts2 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("20"));
}};
Tier tier2 = new Tier()
    .upTo(new BigDecimal("10"))
    .amounts(amounts2);

Map<String, BigDecimal> amounts3 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("30"));
}};
Tier tier3 = new Tier()
    .upTo(new BigDecimal("15"))
    .amounts(amounts3);

Map<String, BigDecimal> amounts4= new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("40"));
}};
Tier tier4 = new Tier()
    .upTo(new BigDecimal("20"))
    .amounts(amounts4);

Map<String, BigDecimal> amounts5 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("50"));
}};
Tier tier5 = new Tier()
    .upTo(new BigDecimal("1000"))
    .amounts(amounts5);

List tiers = new ArrayList();
tiers.add(tier1);
tiers.add(tier2);
tiers.add(tier3);
tiers.add(tier4);
tiers.add(tier5);

PriceCreateRequest priceRequest = new PriceCreateRequest()
    .name("Volume Flat Fee Price")
    .planId(planWithVolumeFlatFees.getId())
    .description("Price with volume flat fees")
    .tiersMode(TiersModeEnum.VOLUME)
    .unitOfMeasure("License")
    .quantity(new BigDecimal("1"))
    .tiers(tiers)
    .startEvent(StartEventEnum.CONTRACT_EFFECTIVE)
    .priceBaseInterval(PriceBaseIntervalEnum.BILLING_PERIOD)
    .deferredRevenueAccountingCode("Subscription Revenue")
    .recognizedRevenueAccountingCode("Subscription Revenue");

Price volumeFlatFeePrice = zuoraClient.prices().createPrice(priceRequest);  

Create usage-based prices

With usage-based pricing, you charge your customers based on how much of your service they use during the billing cycle, instead of explicitly setting quantities, as in the per unit and flat rate pricing. Another difference is that with per-unit and and flat rate pricing you can collect payment for the billing cycle in advance or in arrears. With metered billing you have to collect payment in arrears. You must also record and report usage.

To charge on a per-minute basis for usage with more usage driving the per-minute price lower for the customer. Here is what pricing looks like in Zuora:

  • Product: VoIP service
  • Plan: Per-minute pricing
  • Price:
    For the first 0-60 minutes: $0.25/min.
    For 61-120 minutes: $0.20/min.
    For 120+ minutes: $0.15/min.

With metered usage recurring[usage]=true, you bill your customer in arrears. Based on how much of your service they consume and track their usage with the Usage API. At the end of the billing period, the total usage is multiplied by the unit_amount to calculate how much the customer owes.

See the following code examples:

// 1. Create a product

curl -X POST "https://rest.sandbox.na.zuora.com/v2/products"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{ 
    "name": "VoIP service",
    "description": "Product with a usage price", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

//2. Create a plan

curl -X POST "https://rest.sandbox.na.zuora.com/v2/plans"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Plan with usage price",
    "product_id": "2c94a116ef504f65b5ef1e9e9e8377e1",
    "description": "Plan with a per-minute usage price", 
    "start_date": "2022-04-01", 
    "end_date": "2032-04-01"
}'

//3. Create a price

curl -X POST "https://rest.sandbox.na.zuora.com/v2/prices"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{
    "name": "Per-minute Usage Price",
    "plan_id": "2c921528ef504f65b5ef1e9e9e8362f2",
    "description": "Per minute usage price with tiered and overage pricing", 
    "tiers_mode": "graduated_with_overage",
    "unit_of_measure": "Minutes",
    "recurring": {
        "recurring_on": "account_cycle_date",
        "usage": true,
        "interval": "month",
        "interval_count": 1
    },
    "tiers": [
        {
            "up_to": 60,
            "unit_amounts": {
                "USD": 0.25
            }
        },
        {
            "up_to": 120,
            "unit_amounts": {
                "USD": 0.2
            }
        }
    ],
    "start_event": "contract_effective", 
    "price_base_interval": "billing_period",
    "deferred_revenue_accounting_code": "Credit Card",
    "recognized_revenue_accounting_code": "Credit Card"
}' 
LocalDate startDate = LocalDate.of(2022, 4, 1);
LocalDate endDate = LocalDate.of(2032, 4, 1);

// 1. Create a product

ProductCreateRequest productRequest = new ProductCreateRequest()
    .name('VoIP Service')
    .startDate(startDate)
    .endDate(endDate)
    .description('Product with a usage price');

Product productWithUsagePrice = zuoraClient.products().createProduct(productRequest);

//2. Create a plan

PlanCreateRequest usagePlanRequest = new PlanCreateRequest()
    .name('Plan with usage price')
    .productId(productWithUsagePrice.getId())
    .startDate(startDate)
    .endDate(endDate)
    .description('Plan with a per-minute usage price')
          
Plan planWithUsagePrice = zuoraClient.plans().createPlan(usagePlanRequest);

//3. Create a price

Map<String, BigDecimal> unitAmounts1 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("0.25"));
}};
Tier tier1 = new Tier()
    .upTo(new BigDecimal("60"))
    .unitAmounts(unitAmounts1);

Map<String, BigDecimal> unitAmounts2 = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("0.2"));
}};
Tier tier2 = new Tier()
    .upTo(new BigDecimal("120"))
    .unitAmounts(unitAmounts2);

List tiers = new ArrayList();
tiers.add(tier1);
tiers.add(tier2);

PriceCreateRequest priceRequest = new PriceCreateRequest()
    .name("Per-minute Usage Price")
    .planId(planWithUsagePrice.getId())
    .description("Per minute usage price with tiered and overage pricing")
    .tiersMode(TiersModeEnum.GRADUATED_WITH_OVERAGE)
    .unitOfMeasure("Minutes")
    .recurring(new Recurring()
        .recurringOn(Recurring.RecurringOnEnum.ACCOUNT_CYCLE_DATE)
        .usage(true)
        .interval(IntervalEnum.MONTH)
        .intervalCount(1))
    .tiers(tiers)
    .startEvent(StartEventEnum.CONTRACT_EFFECTIVE)
    .priceBaseInterval(PriceBaseIntervalEnum.BILLING_PERIOD)
    .deferredRevenueAccountingCode("Subscription Revenue")
    .recognizedRevenueAccountingCode("Subscription Revenue");

Price usagePrice = zuoraClient.prices().createPrice(priceRequest);

Create plans that contain multiple prices

Plans can use multiple prices to define different pricing options. The plan description is shared between prices and appears the same on the customer’s receipts and invoices – only the pricing differs.

For example, you offer the software service to your customers. For the basic plan, the subscription fee is charged at a rate of $100 per month, which includes 20 licenses. If your customer needs to purchase more than 20 licenses, extra licenses are charged at $5 per license per month.

  • Product: Software service – Basic
  • Plan: Software Service – Basic Monthly Plan
  • Prices:
    • Flat fee: $100 per month
    • Per-unit price: $5 per unit per month

In this case, you should add the two prices to the same plan by specifying the same plan_id when creating them.

The high-level steps are as follows:

  1. Create the “Software service – Basic” product
  2. Create the monthly plan for “Software service – Basic”
  3. Create the monthly flat fee
  4. Create the monthly per-unit price

See the following code samples for details:

// 1. Create the "Software service - Basic" product

curl -X POST "https://rest.sandbox.na.zuora.com/v2/products"
     -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
     -H "Content-Type: application/json" 
     -d '{ 
           "name": "Software service - Basic",
           "description": "Software service - basic edition", 
           "start_date": "2022-06-01", 
           "end_date": "2032-06-01"
         }' 

//2. Create the monthly plan for "Software service - Basic"

curl -X POST "https://rest.sandbox.na.zuora.com/v2/plans"
     -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
     -H "Content-Type: application/json" 
     -d '{
            "name": "Software Service - Basic Monthly Plan",
            "product_id": "2c94a116ef504f65b5ef1e9e9e8377e1",  
            "description": "Monthly plan of the SaaS service", 
            "start_date": "2022-06-01", 
            "end_date": "2032-06-01"
          }' 

//3. Create the Basic Monthly flat fee

curl -X POST "https://rest.apisandbox.zuora.com/v2/prices"
     -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
     -H "Content-Type: application/json" 
     -d '{
           "name": "Basic Monthly Flat Fee",
           "plan_id": "2c921528ef504f65b5ef1e9e9e8362f2",
           "description": "Monthly flat fee of the Basic Monthly plan", 
           "amounts": {
              "USD": 100
           },
           "recurring": {
              "recurring_on": "account_cycle_date",
              "interval_count": 1,
              "interval": "month",
              "timing": "in_advance"
           },
           "start_event": "contract_effective", 
           "price_base_interval": "billing_period",
           "deferred_revenue_accounting_code": "Subscription Revenue",
           "recognized_revenue_accounting_code": "Subscription Revenue"
         }' 

//4. Create the Monthly per-unit price

curl -X POST "https://rest.sandbox.na.zuora.com/v2/prices"
     -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
     -H "Content-Type: application/json" 
     -d '{
          "name": "Monthly Per Unit Price",
          "unit_of_measure": "License",
          "unit_amounts": {
            "USD": 5
          },
          "recurring": {
            "interval": "month",
            "recurring_on": "account_cycle_date",
            "interval_count": "1",
            "timing": "in_advance"
          },
          "plan_id": "2c921528ef504f65b5ef1e9e9e8362f2",
          "description": "Monthly per unit price", 
          "start_event": "contract_effective", 
          "price_base_interval": "month",
          "quantity": 0,
          "recognized_revenue_accounting_code": "Service Revenue",
          "deferred_revenue_accounting_code": "Service Revenue" 
        }' 
LocalDate startDate = LocalDate.of(2022, 4, 1);
LocalDate endDate = LocalDate.of(2032, 4, 1);

// 1. Create the "Software service - Basic" product

ProductCreateRequest productRequest = new ProductCreateRequest()
      .name('Software service - Basic')
      .startDate(startDate)
      .endDate(endDate)
      .description('Software service - basic edition');
          
Product newProduct = zuoraClient.products().createProduct(productRequest);

//2. Create the monthly plan for "Software service - Basic"

PlanCreateRequest planRequest = new PlanCreateRequest()
      .name('Software Service - Basic Monthly Plan')
      .productId(newProduct.getId())
      .startDate(startDate)
      .endDate(endDate)
      .description('Monthly plan of the SaaS Service');
          
Plan newPlan = zuoraClient.plans().createPlan(planRequest);

//3. Create the Basic Monthly flat fee

Map<String, BigDecimal> monthlyAmounts = new HashMap<String, BigDecimal>() {{
    put("USD", new BigDecimal("100.00"));
}};

PriceCreateRequest monthlyPriceRequest = new PriceCreateRequest()
    .amounts(monthlyAmounts)
    .name("Basic Monthly Flat Fee")
    .priceBaseInterval(PriceBaseIntervalEnum.BILLING_PERIOD)
    .planId(basicMonthlyPlan.getId())
    .description("Monthly flat fee of the Basic Monthly plan")
    .recurring(new Recurring()
        .recurringOn(Recurring.RecurringOnEnum.ACCOUNT_CYCLE_DATE)
        .interval(IntervalEnum.MONTH)
        .intervalCount(1)
        .timing(TimingEnum.ADVANCE)
    )
    .startEvent(StartEventEnum.CONTRACT_EFFECTIVE)
    .deferredRevenueAccountingCode("Subscription Revenue")
    .recognizedRevenueAccountingCode("Subscription Revenue");

Price baseMonthlyPrice = zuoraClient.prices().createPrice(monthlyPriceRequest);

//4. Create the Monthly per-unit price

Map<String, BigDecimal> unitAmount = new HashMap<String, BigDecimal>().put("USD", new BigDecimal("5.00"));
          
PriceCreateRequest priceRequest = new PriceCreateRequest()
      .unitAmounts(unitAmount)
      .unitOfMeasure("License")
      .name("Monthly Per Unit Price")
      .priceBaseInterval(PriceBaseIntervalEnum.MONTH)
      .planId(newPlan.getId())
      .description("Monthly per unit price")
      .recurring(new Recurring()
          .interval(IntervalEnum.MONTH)
          .intervalCount(1)
          .timing(TimingEnum.ADVANCE)
          .recurringOn(Recurring.RecurringOnEnum.ACCOUNT_CYCLE_DATE)
      )
      .quantity(new BigDecimal("0"))
      .startEvent(StartEventEnum.CONTRACT_EFFECTIVE)
      .recognizedRevenueAccountingCode("Service Revenue")
      .deferredRevenueAccountingCode("Service Revenue");

Price newPrice = zuoraClient.prices().createPrice(priceRequest);

List all products

In this use case, we will show you how to retrieve products, plans, and prices from Zuora and use the data in your portal.

A product represents a product or service that your company sells. The pricing is described as plans. A plan represents a collection of prices that your customers may incur when buying your product. When a customer purchases a product, they can pick from one of the available plans.

List all products example

You can use the List all products operation to retrieve all products in your tenant. The List all products operation returns an array of products (paginated, 10 per call), without plans and prices information by default. The response may contain a next_page field, which is the index to the next product that cannot be displayed on the current page. To fetch the next page of the list, set this index as the value of the cursor query parameter in the subsequent request.

To retrieve all plans and prices related to each product, set the value of the expand[] query parameter to plans.prices.

The following example retrieves all products with plans and prices:

curl -X GET "https://rest.apisandbox.zuora.com/v2/products?expand[]=plans.prices"
     -H "Authorization: Bearer 72db3da461ba40c69fb1c2dc440ad204"
     -H "Content-Type: application/json"
List<String> expandParameters = new ArrayList<String>();
expandParameters.add("plans.prices");
ProductListResponse productsWithPlansAndPrices = zuoraClient.products().getProducts(null, expandParameters, null);
System.out.println(expandParameters);

Sign up new subscribers

Suppose that a new customer wants to subscribe to a product offered by you. You need to capture the following information:

  • Basic account information about your new customer
  • The payment method they use to pay
  • The product you will be provisioning for them and the price they will be charged
  • The contract effective date from which the subscription becomes effective

The following examples show how to sign up a new customer, allowing them to create a new subscription together with a new account.

Create a new subscription with a new account example

The following example shows how to create a subscription, passing the customer account and a reference to a plan. To learn about plans, see the Plans API.

curl -X POST "https://rest.sandbox.na.zuora.com/v2/subscriptions" 
  -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
  -H "Content-Type: application/json" 
  -d '{  
      "account_data":{
         "bill_to": {
            "first_name": "Amy",
            "last_name": "Lawrence",
            "email": "amy.lawrence@zuora.com",
	    "address":{
		"line1": "101 Redwood Shors Parkaway",
		"city": "Redwood City",
		"postal_code": "94065",
		"state": "CA",
		"country": "USA"
	     }
         },
         "name": "Amy Lawrence's Account",
         "currency": "USD"
      },
      "subscription_plans": [{
         "plan_id": "8ad095b8813772670181383d05136860"
      }],
      "start_on":{
	 "contract_effective": "2022-08-01"
      }
}'
AccountContactCreateRequest contactCreateRequest = new AccountContactCreateRequest()
    .firstName("Amy")
    .lastName("Lawrence")
    .email("amy.lawrence@zuora.com")
    .address(new Address()
               .line1("101 Redwood Shors Parkaway")
               .city("Redwood City")
               .postalCode("94065")
               .country("USA")
               .state("CA"));

AccountCreateRequest accountCreateRequest = new AccountCreateRequest()
    .name("Amy Lawrence's Account")
    .billTo(contactCreateRequest)
    .currency("USD");

PlanCreateRequest planRequest = new PlanCreateRequest() 
    .name('Monthly Plan') 
    .productId(newProduct.getId()) 
    .startDate('2021-10-20') 
    .endDate('2031-10-19') 
    .description('Gold Product'); 

Plan newPlan = zuoraClient.plans().createPlan(planRequest); 

LocalDate todayDate = LocalDate.now();
String todayDateStr = todayDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
SubscriptionCreateRequest subscriptionCreateRequest = new SubscriptionCreateRequest() 
  .accountData(accountCreateRequest) 
.subscriptionPlans(Collections.singletonList(new SubscriptionChildPlanCreateRequest().planId(newPlan.getId())))
  .startOn(new StartOn().contractEffective(todayDateStr)); 

Subscription createdSubscription = zuoraClient.subscriptions().createSubscription(subscriptionCreateRequest);

Update contact information for an account

Zuora requires two types of contacts to be associated with an account: bill-to contact and sold-to contact. The bill-to contact determines where the invoice should be delivered, whereas the sold-to contact determines how taxes are calculated. If the invoice delivery preference is email, the bill-to contact must contain an email address.

Update contact information example

In this use case, we will update the sold-to contact information of an account using the Update an account operation.

curl --request PATCH
     --url https://rest.apisandbox.zuora.com/v2/accounts/2c92c0f86a8dd422016a9e7a70116b0d --header 'Authorization: Bearer 06a297740b184fc384bc57cbe8a04e53'
     --header 'Content-Type: application/json'
     --data '{
               "sold_to":{
                   "first_name": "John",
                   "last_name": "Doe",
                   "address": {
                       "line1": "No.111, Street ABC",
                       "city": "San Francisco",
                       "state": "CA",
                       "country": "United States"
                    }
                }
     }'
Address soldToAddress = new Address()
    .line1("No.123, Street ABC")
    .city("San Francisco")
    .state("CA")
    .country("United States");

AccountPatchRequest accountPatchRequest = new AccountPatchRequest()
    .soldTo(new AccountContactPatchRequest()
        .firstName("Jane")
        .lastName("Doe")
        .address(soldToAddress));

Account updatedAccount = zuoraClient.accounts().updateAccount(account.getId(),accountPatchRequest);

Create a payment method through payment pages

You can create a payment method using the Create a payment method operation. However, to guarantee PCI-compliance, we recommend that you create payment methods using Zuora’s Payment Pages 2.0 feature.

For more information, see Payment Pages 2.0 implementation overview.

Add a subscription plan to a subscription

Later, if you want to make changes to the subscription, you can use the Update a subscription API operation to update the subscription. You can add subscription plans, remove subscription plans, renew subscriptions by specifying the following fields, respectively:

  • add_subscription_plans
  • remove_subscription_plans
  • renew

Add a subscription plan example

The following example provides an example of updating a subscription by adding a new plan to the created subscription.

curl -X PATCH "https://rest.apisandbox.zuora.com/v2/subscriptions/8ad08f74803a5e3e01803f340e3c2148"
  -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
  -H "Content-Type: application/json" 
  -d '{ 
        "description": "Updated subscription description",
        "add_subscription_plans": [{
          "subscription_plan":{ 
            "plan_id": "8ad09bce8292b8480182a8ea00db35b3",
            "prices":[{
               "price_id": "8ad095b882aa84850182abbe78fd12f1"
             }]
          },
          "start_on": {
             "contract_effective": "2022-08-01",
             "service_activation": "2022-08-01",
             "customer_acceptance": "2022-08-01"
          }
       }]
      }'
LocalDate date = LocalDate.of(2022,8,20);
String oldSubscriptionId = subscription.getId();

SubscriptionItemCreateRequest subscriptionItemCreateRequest = new SubscriptionItemCreateRequest().priceId("8ad095b882aa84850182abbe78fd12f1");

SubscriptionPlanCreateRequest subscriptionPlanRequest = new SubscriptionPlanCreateRequest()
  .planId("8ad09bce8292b8480182a8ea00db35b3")
  .prices(Collections.singletonList(subscriptionItemCreateRequest));

SubscriptionAddPlanPatchRequest addSubscriptionPlanRequest = new SubscriptionAddPlanPatchRequest()
  .subscriptionPlan(subscriptionPlanRequest)
  .startOn((new StartOn()
    .contractEffective(date)
    .customerAcceptance(date)
    .serviceActivation(date)));

SubscriptionPatchRequest updateRequest = new SubscriptionPatchRequest()
  .addSubscriptionPlans(Collections.singletonList(addSubscriptionPlanRequest));

Subscription updatedSubscription = zuoraClient.subscriptions().patchSubscription(oldSubscriptionId,updateRequest);

Remove a subscription plan from a subscription

You can also remove a subscription plan from an existing subscription with the Update subscription API operation.

Remove a subscription plan example

The following code samples provide an example of removing a subscription plan from a created subscription.

curl -X PATCH "https://rest.apisandbox.zuora.com/v2/subscriptions/8ad08f74803a5e3e01803f340e3c2148"
  -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
  -H "Content-Type: application/json" 
  -d '{ 
        "description": "Remove a subscription plan",
        "remove_subscription_plans": [ {
          "subscription_plan_id": "8ad08ccf82afa5d70182afdb2242002f", 
          "start_on": { 
            "contract_effective": "2022-08-20",
            "service_activation": "2022-08-20", 
            "customer_acceptance": "2022-08-20" 
          }
         }]
      }'
LocalDate removePlanDate = LocalDate.of(2022,8,20);
String oldSubscriptionId = createdSubscription.getId();

SubscriptionRemovePlanPatchRequest removeSubscriptionPlanRequest = new SubscriptionRemovePlanPatchRequest()
    .subscriptionPlanId("8ad09b7d80936cd1018098c227be79e4")
    .startOn((new StartOn()
        .contractEffective(removePlanDate)
        .customerAcceptance(removePlanDate)
        .serviceActivation(removePlanDate)));

SubscriptionPatchRequest updateRequest = new SubscriptionPatchRequest().removeSubscriptionPlans(Collections.singletonList(removeSubscriptionPlanRequest));

Subscription updatedSubscription = zuoraClient.subscriptions().patchSubscription(oldSubscriptionId,updateRequest);

Renew a subscription

The Update subscription API operation allows you to renew a subscription that is about to expire.

Note that only termed subscriptions can be renewed.

Renew a subscription example

The following code example renews the subscription (id = 8ad08f74803a5e3e01803f340e3c2148) on 2023-01-01. The renewal term is 12 months.

curl -X PATCH "https://rest.apisandbox.zuora.com/v2/subscriptions/8ad08f74803a5e3e01803f340e3c2148"
  -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
  -H "Content-Type: application/json" 
  -d '{
         "description": "Renew a subscription", 
         "renew":{
            "start_on": {
                "contract_effective": "2023-01-01"
            }
          },
         "terms": { 
            "renewal_term": { 
                "interval": "month", 
                "interval_count": 12, 
                "type": "termed"
            }
         }
      }'
LocalDate renewStartDate = LocalDate.of(2023,1,1);
String subscriptionId = createdSubscription.getId();

SubscriptionTermPatchRequest renewalTerm = new SubscriptionTermPatchRequest()
    .renewalTerm(new Term()
        .type(Term.TypeEnum.TERMED)
        .interval(Term.IntervalEnum.MONTH)
        .intervalCount(12)

SubscriptionRenewPatchRequest renewSubscriptionRequest = new SubscriptionRenewPatchRequest()
    .startOn((new StartOn()
        .contractEffective(renewStartDate)));

SubscriptionPatchRequest updateRequest = new SubscriptionPatchRequest()
    .renew(renewSubscriptionRequest)
    .terms(renewalTerm)
    .description("Renew a subscription");

Subscription updatedSubscription = zuoraClient.subscriptions().patchSubscription(subscriptionId,updateRequest);

Cancel a subscription

In this use case, the end subscriber wants to cancel a subscription. When an end subscriber decides to terminate their subscription, there are three ways for the merchant to manage billing:

  • Cancel the subscription and make the cancellation effective after the last invoiced period
    After the cancellation, billing will stop immediately for the subscription. The cancellation is effective after the latest invoice through date.
    To use this option for subscription cancellation, set the cancel_at field to invoice_period_end.
  • Cancel the subscription and make the cancellation effective at the end of the current subscription term.
    This option is applicable only to termed subscriptions. After the cancellation, billing will continue until the end of the current subscription term and then stop. If the subscription is set to auto-renew when the subscription is created, the auto-renewal will be stopped when the subscription is canceled.
    To use this option for subscription cancellation, set the cancel_at field to subscription_term_end.
  • Cancel the subscription and make the cancellation effective on a specific date
    • If the cancellation is made effective during a service period that has already been billed, Zuora will credit back the prorated amount from the cancellation effective date.
    • If the cancellation is made effective after the billed through date, Zuora will continue to bill until the cancellation effective date. After that, billing will stop.

To use this option for subscription cancellation, set the cancel_date field to a specific date.

Cancel a subscription example

The following code example demonstrates how to cancel a subscription at the end of billing period while specifying the processing option:

curl --request PATCH \
     --url 'https://rest.apisandbox.zuora.com/v2/subscriptions/​​A-S00000035/cancel' \
     --header 'Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3' \
     --header 'Content-Type: application/json'\
     --data '{
                "cancel_at": "invoice_period_end",
                "processing_options": {
                    "collection_method": "collect_payment",
                    "document_date": "2023-01-01"
                }
             }'
LocalDate documentDate = LocalDate.of(2022,9,1);
String subscriptionNumber = "A-S00013446";

CancelSubscriptionRequest cancelRequest = new CancelSubscriptionRequest()
    .cancelAt(CancelAtEnum.INVOICE_PERIOD_END)
    .processingOptions(new ProcessingOptions()
        .documentDate(documentDate)
        .collectionMethod(CollectionMethodEnum.COLLECT_PAYMENT));

Subscription canceledSubscription = zuoraClient.subscriptions().cancelSubscription(subscriptionNumber,cancelRequest);

Suspend a subscription

If the end subscriber requests to suspend or pause a subscription, use the Pause a subscription operation to do it.

It is also required to specify the rules for pause a subscription. For example, the subscription can be paused on a specific date or after a certain number of periods from today.

  • To pause a date on a certain date, specify pause_date.
  • To pause a date at the end of one billing period, specify the following fields:
    • pause_at
    • pause_interval
    • pause_interval_count

You can optionally specify the resume_behavior field to define the behavior when the paused subscription resumes.

Suspend a subscription example

The following example pauses an active subscription:

curl --request POST 
     --url 'https://rest.apisandbox.zuora.com/v2/subscriptions/A-S00000035/pause' 
     --header 'Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3' 
     --header 'Content-Type: application/json' 
     --data '{
                "pause_at":"specific_period",
                "pause_interval": "month",
                "pause_interval_count": 1,
                "resume_behavior": {
                    "extend_term": true
                 }
              }
String subscriptionId = "8ad09c4b82aa84900182af4b0d6d6713";

PauseSubscriptionRequest pauseRequest = new PauseSubscriptionRequest()
    .pauseAt(PauseSubscriptionRequest.PauseAtEnum.SPECIFIC_PERIOD)
    .pauseInterval(PauseSubscriptionRequest.PauseIntervalEnum.MONTH)
    .pauseIntervalCount(new BigDecimal(1))
    .resumeBehavior(new ResumeSubscriptionRequest().extendTerm(true));

Subscription pausedSubscription = zuoraClient.subscriptions().pauseSubscription(subscriptionId, pauseRequest);

Resume a subscription

When a subscription is in the Suspended status, the only action you can take is to resume a suspended subscription with the Resume a subscription operation.

The resume date cannot be earlier than the suspend date and cannot be later than the subscription term end date.

Resume a subscription example

The following example resumes the subscription that is suspended from the previous section.

curl --request POST      
     --url 'https://rest.apisandbox.zuora.com/v2/subscriptions/8ad08f74803a5e3e01803f340e3c2148/resume'      --header 'Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3'      
     --header 'Content-Type: application/json'      
     --data '{ 
                "extend_term": true,
                "resume_date": "2022-09-10"
             }' 
ResumeSubscriptionRequest resumeRequest = new ResumeSubscriptionRequest()
    .extendTerm(true)
    .resumeDate("2022-09-10");
 
Subscription resumedSubscription = zuoraClient.subscriptions().resumeSubscription(pausedSubscription.getId(), resumeRequest);

Create a billing document

Billing documents represent your customer’s invoices, credit memos, and debit memos.

Invoices are statements of amounts owed by a customer, and are either generated one-off, or generated periodically from a subscription. They contain invoice items, and proration adjustments that may be caused by changes to a subscription. If your invoice is configured to be charged automatically, Zuora automatically finalizes your invoice and attempts payment otherwise Zuora will email the invoice to your customer and await payment. Any customer credit memos may be applied before determining the amount due for the invoice, which is the amount that will be charged.

Create an invoice example

Assume the billing timing of the recurring price that your customer subscribes to is in_advance. After your customer has created a subscription, you need to create an invoice and bill it to your customer.

The following code sample creates an invoice for the subscription of the Gold product and post it to your customer’s account.

curl -X POST "https://rest.apisandbox.zuora.com/v2/billing_documents"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3"
-H "Content-Type: application/json"
-d '{
    "account_id": "2c92c0f96abc17de016abd62bd0c5854",
    "pay": false,
    "description": "invoice of subscription for Gold product",
    "document_date": "2022-02-01",
    "type": "invoice",
    "post": true,
    "items": [
     {
          "amount": 300,
          "booking_reference": "PE2FGW",
          "item_date": "2022-02-01",
          "subscription_item_name": "subscription item 1",
          "description": "a new invoice item",
          "quantity": 2,
          "service_end": "2023-02-01",
          "service_start": "2022-02-01"
      }]
}'
LocalDate todayDate = LocalDate.now();

BillingDocumentItemCreateRequest invoiceItemRequest = new BillingDocumentItemCreateRequest()
  .amount(new BigDecimal(300.00))
  .bookingReference("PE2FGW")
  .itemDate("2022-02-01")
  .subscriptionItemName("subscription item 1")
  .description("a new invoice item")
  .quantity(new BigDecimal(2))
  .serviceEndDate("2023-09-01")
  .serviceStartDate("2022-09-01");

BillingDocumentCreateRequest invoiceRequest = new BillingDocumentCreateRequest()
  .accountId(newAccount.getId())
  .pay(false)
  .description("new invoice")
  .documentDate(todayDate)
  .post(true)
.type(BillingDocumentCreateRequest.TypeEnum.INVOICE)
.items(Collections.singletonList(invoiceItemRequest));

BillingDocument newInvoice = zuoraClient.billingDocuments().postBillingDocument(invoiceRequest);

Create a payment

The Payment object holds all of the information about a payment, including the payment amount and to which billing documents the payment is applied.

Pay an invoice example

The following code sample creates a payment to the invoice created for your customer account, Amy Lawrence (account_id=2c92c0f96abc17de016abd62bd0c5854), using the payment method (payment_method_id=8f64d4d7b1b989f6c571d931f84e0458) associated with this account.

curl -X POST "https://rest.sandbox.na.zuora.com/v2/payments"
-H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
-H "Content-Type: application/json" 
-d '{ 
    "account_id": "2c92c0f96abc17de016abd62bd0c5854",
    "amount": 50,
    "payment_date": "2022-08-20",
    "payment_method_id": "8f64d4d7b1b989f6c571d931f84e0458",
    "external": true,
    "currency": "USD"
}'
LocalDate todayDate = LocalDate.now();

PaymentCreateRequest paymentCreateRequest = new PaymentCreateRequest()
    .accountId(newAccount.getId())
    .amount(50)
    .paymentDate(todayDate)
    .paymentMethodId(createdPaymentMethod.getId())
    .external(true)
    .currency("USD");

Payment newPayment = zuoraClient.payments().createPayment(paymentCreateRequest);

Create a refund

In Zuora, you can refund fully or partially unapplied payments to your end subscribers by refunding from payment.

When you issue a refund, the amount field is required, which is the total amount of the refund.

The total amount of the refund cannot exceed the unapplied amount of the associated payment. If you want to refund the applied amount of the associated payment, you must first unapply the applied amount from the billing documents, and then refund the unapplied amount to your end subscribers.

The external filed indicates whether this refund is an external refund or an electronic refund. External refunds are performed outside of Zuora and electronic refunds are issued by using supported payment gateways.

If the refund type is electronic, you cannot specify the refund date because the electronic refund will automatically refund money to the end subscriber’s credit card.

Create a refund example

The following example uses the Create a refund operation to refund part of the unapplied amount ($10) from the payment:

curl -X POST "https://rest.apisandbox.zuora.com/v2/refunds"
     -H "Authorization: Bearer 6d151216ef504f65b8ff6e9e9e8356d3" 
     -H "Content-Type: application/json" 
     -d '{ 
            "account_id": "8ad09b7d8292b85d0182a4d6f875225a",
            "amount": 10,
            "payment_id": "8ad0887e82d94f5d0182d967a49c1a63",
            "external": false
          }'

Introduction to query parameters

When you query records from Zuora objects, the following query parameters enable you to flexibly customize the returned results:

  • cursor: A cursor for use in pagination. cursor defines the starting place in a list. For instance, if you make a list request and receive 100 objects, ending with next_page=W3sib3JkZXJ=, your subsequent call can include cursor=W3sib3JkZXJ= in order to fetch the next page of the list.
  • expand[]: With this query parameter specified, you can reduce the number of requests you make to the Zuora API by expanding objects in responses. See the “Expand responses” section below for more information.
  • filter[]: The filter query string. See the “Filter lists” section below for more information.

Expand responses

This section describes how to request additional properties from the API. You will learn to modify your requests to include:

  • properties from related objects
  • properties from distantly related objects
  • additional properties on all objects in a list

The expandable values for each objects are also provided for easy reference.

How the expand parameter works

The Zuora API is organized into resources represented by objects with state, configuration and contextual properties. These objects all have unique IDs that you can use to retrieve, update, and delete them. The API also uses these IDs to link related objects together. A Billing Document, for example, links to an Account by the Account ID.

{
  "id": "2c93808457d787030157e031d86c4c57",
  "account_id": "402892c74c9193cd014c91d35b0a0132",
  ...
}

In cases where you need information from a linked object, you can retrieve the linked object in a new call using its ID. However, this approach requires two API requests to access just one value. If you need information from multiple linked objects, each would also require separate requests, which adds to the latency and complexity of your application.

The API has an expand[] query parameter that allows you to retrieve linked objects in a single call, adding the object with all its properties and values.

For example, if you want to access details of the subscriptions and payment methods associated with a customer account, you would retrieve the account and pass the subscription and payment_method properties to the expand array, which tells Zuora to include the entire Subscriptions and Payment Method objects in the response:

curl -X GET \
'https://rest.sandbox.na.zuora.com/v2/accounts?expand%5B%5D=subscriptions&expand%5B%5D=payment_methods' \
-H 'Authorization: Bearer aa69290d875f4cfb97b226135ce278ad'
Account account = zuoraClient.accounts().getAccount(
"2c92c0f86cbe335a016cbece4a434ada",
Arrays.asList("subscriptions", "payment_methods")
);


It will return the subscriptions and payment methods associated with the account:

{
"id": "2c92c0f96abc17de016abd62bd0c5854",
...
"account_number": "RC-00000017",
"payment_methods": {
  "data": [
  {
    "id": "2c92c0f9710b79bd01711219e3ed2d9a",
    "account_id": "2c92c0f96abc17de016abd62bd0c5854",
    "type": "ach_debit",
  ...
  }
  ]
},
"subscriptions":
{
  "data": [
  {
    "id": "8ad0935e80bc8f360180c6f5a6e83ace",
    "subscription_number": "OpportunityNum1",
    "state": "Active",
    "account_id": "2c92c0f96abc17de016abd62bd0c5854",
  }
  ],
...
}
}

Expand multiple levels

If the value you want is nested deeply across multiple linked resources, you can reach it by recursively expanding using dot notation. For instance, if you want to know the payment method and the subscription plans of the subscriptions associated with an account, you can expand the subscription plan of the subscription and the payment method by passing subscriptions.subscription_plans and payment_methods into the expand array.

curl -X GET \
'https://rest.sandbox.na.zuora.com/v2/accounts?expand%5B%5D=subscriptions.subscription_plans&expand%5B%5D=payment_methods' \
-H 'Authorization: Bearer aa69290d875f4cfb97b226135ce278ad'
Account account = zuoraClient.accounts().getAccount(
"2c92c0f86cbe335a016cbece4a434ada", Arrays.asList("subscriptions.subscription_plans", "payment_methods")
);

Request non-default properties

If you query on a billing document, its included items are returned without details by default. You will not get any meaningful data in the returned items object. The details of this property is returned in responses only if the expand[] parameter is specified. For example:

curl -X GET "https://rest.sandbox.na.zuora.com/v2/billing_documents/2c93808457d78703011d86c4c57" 
> -d "expand[]=items"
> -H "Authorization: Bearer 6e3b8958cc2b4b4bbfca2e4ab8d75126"
BillingDocumentListResponse response = zuoraClient.billingDocuments().getBillingDocuments(null,Collections.singletonList("item"),null,null);
System.out.println(response);

Expandable objects and fields

Not all objects or objects can be expanded. See the following table for a list of objects and the supported expand[] values:

Resource Supported expand[] value
Account payment_methods
billing_documents
bill_to
sold_to
subscriptions
subscriptions.subscription_plans
subscriptions.subscription_plans.plan
subscriptions.subscription_plans.subscription_items
Subscription subscription_plans
subscription_plans.subscription_items
account
account.bill_to
account.sold_to
account.payment_methods
account.payments
account.billing_documents
Subscription Plan subscription
subscription_items
Billing Document items
items.taxation_items
account
account.payment_methods
account.payments
account.billing_documents
account.bill_to
account.sold_to
account.subscriptions
account.subscriptions.subscription_plans
Billing Document Item subscription
subscription_items
taxation_items
Refund account
account.payment_methods
account.payments
account.billing_documents
account.bill_to
account.sold_to
account.subscriptions
account.subscriptions.subscription_plans
Payment account
account.payment_methods
account.billing_documents
account.bill_to
account.sold_to
account.subscriptions
account.subscriptions.subscription_plans
Product plans
plans.prices
Plan prices

Filter lists

Filter query syntax

A filter query clause consists of the following components:

  • a field
  • an operator
  • a value

The filter query syntax is as follows:

{field}.{operator}:{value}

The following table lists an example clause and the breakdown components:

clause email.EQ:alawrence@zuora.com
field email
operator EQ
value alawrence@zuora.com

You can combine multiple filter query clauses by separating them as different array elements. Note that the clauses are combined with AND logic.

See the following sections for more information:

  • Supported operators and corresponding examples of using
  • Supported query fields for each object

Note: You can use any indexed custom field in your query filters and the fields documented here for each object.

Supported operators

The following table lists all supported operators that you can use to construct a list filter query, and an example for each operator.

Operator Description Example
EQ Exact match operator currency.EQ:EUR
NE Returns objects that do not match the clause currency.NE:CAN
LT Less than operator quantity.LT:200
LTE Less than or equal operator amount.LTE:100
GT Greater than operator quantity.GT:200
GTE Greater than or equal operator amount.GTE:100
SW Starts with operator account_name.SW:Acc
Field types and operators

All search fields support exact and case-sensitive matching with EQ and NE.

Some fields like email and name support case-sensitive matching with SW.

Some other fields, such as amount, support numeric comparators like LT, LTE, GT, and GTE.

Supported query fields - accounts

The following table summarizes the supported query fields for the Account object.

Field Example usage
updated_time updated_time:GT:2020-03-10T07:12:12-07:00
batch batch:EQ:batch1
bill_cycle_day bill_cycle_day.EQ:30
bill_to_id bill_to_id.EQ:2c92c08a6246fdf101626b1b3fe0144b
sold_to_id sold_to_id.NE:2c92c08a6246fdf101626b1b3fe0144b
communication_profile_id communication_profile_id.EQ:2c92c0f95be68649015bf14e001f2760
crm_id crm_id.SW:SF
currency currency.NE:GBP
default_payment_method_id default_payment_method_id.EQ:402892c74c9193cd014c96bbe7d901fd
billing_document_settings.invoice_template_id billing_document_settings.invoice_template_id.SW:INV
name name.SW:Amy
parent_account_id parent_account_id.EQ:402892c74c9193cd014c96bbe7c101f9
state state.EQ:Washington
account_number account_number.EQ:A100032

Supported query fields - contacts

The following table summarizes the supported query fields for the Contact object.

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
first_name first_name.SW:Amy
account_id account_id.EQ:402892c74c9193cd014c96bbe7c101f9
address.country address.country.EQ:France
email email.EQ:alawrence@zuora.com

Supported query fields - subscriptions

The following table summarizes the supported query fields for the Subscription object.

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
account_id account_id.EQ:402892c74c9193cd014c96bbe7c101f9
contract_effective_date contract_effective_date.EQ:2022-01-01
invoice_account_id invoice_account_id:EQ:2c92c0f958fffd7801591ad2dca919fd
state state.EQ:paused
current_term.start_date current_term.start_date.LTE:2022-04-01
subscription_number subscription_number.EQ:SUB10000

Supported query fields - subscription plans

The following table summarizes the supported query fields for the Subscription Plan object.

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
subscription_id subscription_id.EQ:8ad09c4b80da79ad0180dd1c0f5937cb

Supported query fields - billing documents

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
document_date document_date.GTE:2022-01-01
account_id account_id.EQ:402892c74c9193cd014c96bbe7c101f9
state state.NE:paid
type type.EQ:invoice
billing_document_number billing_document_number.NE:INV10001

Supported query fields - billing document items

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
type type.EQ:credit_memo
subscription_id subscription_id.NE:402892c74c9193cd014c96bbe7c101f9

Supported query fields - payment methods

The following table summarizes the supported query fields for the Payment Method object.

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
account_id account_id.EQ:402892c74c9193cd014c96bbe7c101f9
ach_debit.bank_account_name ach_debit.bank_account_name.EQ:TestAccount
ach_debit.bank_name ach_debit.bank_name.EQ:AMEX
state state.EQ:active
sepa_debit.business_identification_code sepa_debit.business_identification_code.EQ:2EAC19
billing_details.address.country billing_details.address.country.NE:Germany
card.last4 card.last4.EQ:1099
paypal_express.baid paypal_express.baid
.EQ:123456
paypal_express_native.baid paypal_express_native.baid.EQ:654321
type type.EQ:ach_debit

Supported query fields - payments

The following table summarizes the supported query fields for the Payment object.

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
account_id account_id.EQ:402892c74c9193cd014c96bbe7c101f9
payment_date payment_date.GT:2022-01-01
gateway_order_id gateway_order_id.EQ:12345678
gateway_state gateway_state.EQ:active
payment_method_id payment_method_id.EQ:402892c74c9193cd014c96bbe7d901fd
payment_number payment_number.NE:1a2b3c4d
reference_id reference_id.EQ:12345
state state.NE:processed

Supported query fields - refunds

The following table summarizes the supported query fields for the Refund object.

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
account_id account_id.EQ:402892c74c9193cd014c96bbe7c101f9
payment_method_id payment_method_id.EQ:402892c74c9193cd014c96bbe7d901fd
reason_code reason_code.EQ:user canceled transaction
refund_number refund_number.NE:RE1234

Supported query fields - products

The following table summarizes the supported query fields for the Product object.

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
name name.SW:ZUO
sku sku.EQ:SKU123
refund_number refund_number.NE:RE1234

Supported query fields - plans

The following table summarizes the supported query fields for the Plan object.

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
name name.SW:MONTHLY
product_id product_id.NE:8ad08aef7ffdebb80180003bd3272789

Supported query fields - prices

The following table summarizes the supported query fields for the Price object.

Field Example usage
updated_time updated_time.GT:2020-03-10T07:12:12-07:00
plan_id plan_id.EQ:8ad08e017ffdeba30180003bd58533ea
charge_model charge_model.NE:Flat Fee Pricing
recurring.on recurring.on.EQ:wednesday

Error handling

Your Zuora integration may have to deal with errors when making requests to the Zuora API.

Zuora uses conventional HTTP response codes to indicate the success or failure of an API request. In general:

  • Codes in the 2xx range indicate success.
  • Codes in the 4xx range indicate an error that failed given the information provided (for example, a required parameter was omitted, a payment attempt failed, etc.).
  • Codes in the 5xx range indicate an error with Zuora’s servers.

Some 4xx errors that could be handled programmatically include an error code that briefly explains the error reported.

An error response contains the following attributes:

Attribute Type Description
type enum Type of the error. See the “Error types” section below for details.
code string An error code indicating the reported error. See the “Error codes” section below for details.
message string A human-readable message providing more details about the error.
parameter string If the error is parameter-specific, it shows the parameter related to the error. For example, you can use this attribute to display a message near the correct form field.

HTTP status codes

The following table lists the HTTP status codes you might receiving when working with the Simple API:

HTTP status code Description
200 – OK Everything worked as expected.
201 – Created Everything worked as expected and a resource was created.
202 – Accepted Your request has been accepted, but processing has not been completed and may not have been started.
400 – Bad Request The request contains invalid parameters.
401 – Unauthorized The request requires user authentication. Resend the request with valid authentication credentials for the resource.
403 – Forbidden Access is forbidden to users with your authentication credentials.
404 – Not Found The server cannot find the requested resource.
408 – Request Timeout The server has decided to close this connection rather than continue waiting.
409 – Conflict The request conflicts with the current state of the target resource.
429 – Too Many Requests Too many requests hit the API too quickly. We recommend an exponential backoff of your requests.
500, 501, 502, 503, 504 – Server Errors Something went wrong on Zuora’s end.

Error types

The following table lists values of the type field in the error response, and their corresponding description:

Error Type Description
bad_request The request contains invalid parameters.
unauthorized The request requires user authentication. Resend the request with valid authentication credentials for the resource.
forbidden Access is forbidden to users with your authentication credentials.
not_implemented The server does not recognize the request method and is incapable of supporting it.
conflict The request conflicts with the current state of the target resource.
not_found The server cannot find the requested resource.
locked This request cannot be processed because the objects this request is trying to modify are being modified by another process.
too_many_requests Too many requests hit the API too quickly. We recommend an exponential backoff of your requests.
internal_server_error Something went wrong on Zuora’s end.

Error codes

Some errors include an error code – a short string with a brief explanation.

Below is a list of possible error codes, along with additional information about how to resolve them.

Error code Description
invalid_parameter One or more of the parameters requires a value of a specific type, but the values provided were a different type. Make sure that only supported values are provided for each attribute. Refer to the Simple API Reference to look up the type of data each attribute supports.
unknown_parameter The request contains one or more unexpected parameters. Remove these parameters and try again.
missing_parameter One or more required values are missing. Check our Simple API Reference to see which values are required to create or modify the specified resource.
parameters_exclusive Two or more mutually exclusive parameters were provided. Check our Simple API Reference or the returned error message to see which values are permitted when creating or modifying the specified resource.
invalid_request The request could not be understood by the server due to malformed syntax. Check the Simple API Reference to see how to create or modify the specified resource and modify your request accordingly.
not_found The requested resource does not exist.
card_error An error occurred while processing the card. Try again later or with a different payment method.
authorization_token_expired The authorization token provided has expired. Obtain a new authorization token and try again.
lock_timeout This object cannot be accessed right now because another API request or Zuora process is currently accessing it. If you see this error intermittently, retry the request. If you see this error frequently when making multiple concurrent requests to a single object, submit your requests serially or at a lower rate. See our rate limit documentation for more details.
resource_already_exists A resource with a user-specified identifier already exists. Use a different and unique value for the identifier such as account_number and try again.

Note: This error code only applies to a resource referenced in a POST request. The error type for such an error is bad_request instead of not_found.

resource_not_found The resource identifier provided is not found.

Note: This error code applies to a resource referenced in a POST, PUT, or PATCH request. For example, when creating a payment method for an account by specifying either an account_number or account_id that does not exist. It will result in an error where the type is bad_request instead of not_found.

Handling errors

Use the following template to handle errors:

try {
  // Use Zuora's library to make requests...
} catch (RateLimitException e) {
  // Too many requests made to the API too quickly
} catch (InvalidRequestException e) {
  // Invalid parameters were supplied to Zuora's API
} catch (AuthenticationException e) {
  // Authentication with Zuora's API failed (maybe you changed API keys recently)
} catch (APIConnectionException e) {
  // Network communication with Zuora failed
} catch (ZuoraException e) {
  // Display a very generic error to the user, and maybe send yourself an email
} catch (Exception e) {
  // Something else happened, completely unrelated to Zuora
}