Catalog
The Catalog
is at the heart of the Kill Bill subscription and billing systems. It provides complete current information on products available, subscription plans, billing options, and much more. Each tenant has a single catalog, but different tenants may have completely different catalogs.
The catalog for a given tenant may be updated to new versions from time to time. This provides the ability to deprecate old products, add new ones, or change prices for existing products. Older versions remain available in case they are needed. If a new version is uploaded, new subscriptions will use the new version, but existing subscriptions may either depend on their original versions (grandfathering use case) or use the latest version (price update use case). Please refer to the catalog section of our subscription billing documentation for additional details.
KAUI, our admin UI, provides the ability to upload a simple plan. The simple plan provides a way to ease testing and to play with the system. See API section Simple Plan.
A tenant has several options for setting up their catalog. You can choose the option that best meets your needs:
- Use the default test catalog that ships with Kill Bill by creating a tenant with
useGlobalDefault=true
- Use the Simple Plan API from KAUI to get started quickly (no need to create an XML catalog, simply use the UI and add the plans you need).
- Write your own complete catalog as an XML file and upload it. Some examples of catalog can be found in our test repo. For validation, check our manual or use our cloud validation tool after creating an account.
- Write a custom Catalog plugin. This is only for advanced users with special needs.
For a full discussion of the KillBill catalog, see the Catalog section in the Subscription Guide.
The Catalog
API offers basic CRUD operations, allowing you to upload, retrieve and delete catalog versions.
Catalog Resource
At a very high level, the Catalog consists of the following main components:
Products
: List of products available - e.g Gold product.Plans
: List of subscription plans available for each product - e.g gold-monthly, monthly subscription for the Gold product.Rules
: Business rules for subscriptions - e.g. when certain changes should take effect.Price Lists
: Lists of applicable Plans.
Full details about the elements of a Catalog are given in the links cited above. The Catalog is maintained as an XML file.
CatalogValidation Resource
Represents the result of validating a catalog.
It includes the following attribute:
Name | Type | Generated by | Description |
---|---|---|---|
catalogValidationErrors | list | system | List of CatalogValidationError (see next) |
CatalogValidationError:
Represents a catalog validation error.
It includes the following attributes:
Name | Type | Generated by | Description |
---|---|---|---|
errorDescription | string | system | Description about the error |
Catalog
Upload a catalog as XML
This endpoint uploads a complete catalog in XML format. This becomes the current version of the Catalog for this Tenant.
Note that the naming for the various entities is based on what the XML spec specifies, and in particular the name
elements need to be globally unique in the catalog and must conform to the XML NCName
definition. This means that they cannot contain symbol characters like :, @, $, %, &, /, +, ,, ;,, whitespace characters or parentheses, and they cannot begin with a number, dot or minus character.
HTTP Request
POST http://127.0.0.1:8080/1.0/kb/catalog/xml
Example Request:
curl -v \
-X POST \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Content-Type: text/xml" \
-H "Accept: application/json" \
-H "X-Killbill-CreatedBy: demo" \
-H "X-Killbill-Reason: demo" \
-H "X-Killbill-Comment: demo" \
-d '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><catalog> ...' \
"http://127.0.0.1:8080/1.0/kb/catalog/xml"
import org.killbill.billing.client.api.gen.CatalogApi;
import java.nio.file.Files;
import java.nio.file.Path;
protected CatalogApi catalogApi;
Path filePath = Path.of("H:/killbill/spycarcatalog.xml");
String body = Files.readString(filePath);
catalogApi.uploadCatalogXml(body, requestOptions);
user = 'user'
reason = 'reason'
comment = 'comment'
catalog = KillBillClient::Model::Catalog
catalog_file_xml = File.read("H:/killbill/catalog.xml")
catalog.upload_tenant_catalog(catalog_file_xml,
user,
reason,
comment,
options)
catalogApi = killbill.CatalogApi()
xml_catalog = open("../resources/SpyCarBasic.xml", "r+").read()
catalogApi.upload_catalog_xml(xml_catalog,
created_by='demo',
reason='reason',
comment='comment')
const fs = require('fs');
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const content = fs.readFileSync('H:/killbill/catalog.xml').toString();
const response: AxiosResponse<string, any> = await catalogApi.uploadCatalogXml(content, 'created_by');
$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";
$apiInstance = $client->getCatalogApi();
$filename = "H:/killbill/catalog.xml";
$fileContents = file_get_contents($filename);
$apiInstance->uploadCatalogXml($fileContents,$xKillbillCreatedBy,$xKillbillReason,$xKillbillComment);
Request Body
Contains the complete catalog in XML format
Query Parameters
None.
Response
If successful, returns a status code of 201 and an empty body.
Retrieve the catalog as XML
This endpoint retrieves the Catalog for a specified date in XML format. If there are multiple versions, the latest version with an effective date not later than the requested date is returned. If the effective date for all versions is greater than the requested date, the earliest version is returned.
For example, suppose there are two versions of the catalog, the current version dated 2020-01-01 (Jan. 1, 2020) and a previous version dated 2019-01-01. Then
- A request with no effective date would return all the available catalog versions
- A request with an effective date of 2020-01-01 or later would retrieve the current version
- A request with an effective date of 2019-01-01 or later, but before 2020-01-01, would retrieve the previous version
- A request with an effective date earlier than 2019-01-01 would retrieve the previous version, as it is the earliest version available.
HTTP Request
GET http://127.0.0.1:8080/1.0/kb/catalog/xml
Example Request:
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Accept: text/xml" \
"http://localhost:8080/1.0/kb/catalog/xml"
import org.killbill.billing.client.api.gen.CatalogApi;
import org.joda.time.DateTime;
protected CatalogApi catalogApi;
DateTime requestedDate = null;
UUID accountId = null;
String catalog = catalogApi.getCatalogXml(requestedDate,
accountId,
requestOptions);
catalog = KillBillClient::Model::Catalog
requested_date = nil
catalog_xml = catalog.get_tenant_catalog_xml(requested_date,options)
catalogApi = killbill.CatalogApi()
catalog_xml = catalogApi.get_catalog_xml()
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const catalogXml: AxiosResponse<string, any> = await catalogApi.getCatalogXml();
$apiInstance = $client->getCatalogApi();
$catalogXml = $apiInstance->getCatalogXml();
Example Response:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<catalogs>
<versions>
<version>
<effectiveDate>2013-02-08T00:00:00Z</effectiveDate>
<catalogName>SpyCarBasic</catalogName>
<currencies>
<currency>USD</currency>
<currency>GBP</currency>
</currencies>
<units/>
<products>
<product name="Basic" prettyName="Basic">
<category>BASE</category>
<included/>
<available/>
<limits/>
</product>
<product name="Sports" prettyName="Sports">
<category>BASE</category>
<included/>
<available/>
<limits/>
</product>
<product name="Standard" prettyName="Standard">
<category>BASE</category>
<included/>
<available/>
<limits/>
</product>
<product name="Super" prettyName="Super">
<category>ADD_ON</category>
<included/>
<available/>
<limits/>
</product>
</products>
<rules>
<changePolicy>
<changePolicyCase>
<policy>IMMEDIATE</policy>
</changePolicyCase>
</changePolicy>
<changeAlignment>
<changeAlignmentCase>
<alignment>START_OF_BUNDLE</alignment>
</changeAlignmentCase>
</changeAlignment>
<cancelPolicy>
<cancelPolicyCase>
<policy>IMMEDIATE</policy>
</cancelPolicyCase>
</cancelPolicy>
<createAlignment>
<createAlignmentCase>
<alignment>START_OF_BUNDLE</alignment>
</createAlignmentCase>
</createAlignment>
<billingAlignment>
<billingAlignmentCase>
<alignment>ACCOUNT</alignment>
</billingAlignmentCase>
</billingAlignment>
<priceList>
<priceListCase>
<toPriceList>DEFAULT</toPriceList>
</priceListCase>
</priceList>
</rules>
<plans>
<plan name="basic-annual" prettyName="basic-annual">
<product>Basic</product>
<recurringBillingMode>IN_ADVANCE</recurringBillingMode>
<initialPhases/>
<finalPhase type="EVERGREEN">
<duration>
<unit>UNLIMITED</unit>
<number>-1</number>
</duration>
<recurring>
<billingPeriod>ANNUAL</billingPeriod>
<recurringPrice>
<price>
<currency>USD</currency>
<value>1000</value>
</price>
</recurringPrice>
</recurring>
<usages/>
</finalPhase>
<plansAllowedInBundle>-1</plansAllowedInBundle>
</plan>
<plan name="sports-monthly" prettyName="sports-monthly">
<product>Sports</product>
<recurringBillingMode>IN_ADVANCE</recurringBillingMode>
<initialPhases>
<phase type="TRIAL">
<duration>
<unit>DAYS</unit>
<number>30</number>
</duration>
<fixed type="ONE_TIME">
<fixedPrice/>
</fixed>
<usages/>
</phase>
</initialPhases>
<finalPhase type="EVERGREEN">
<duration>
<unit>UNLIMITED</unit>
<number>-1</number>
</duration>
<recurring>
<billingPeriod>MONTHLY</billingPeriod>
<recurringPrice>
<price>
<currency>GBP</currency>
<value>375.00</value>
</price>
<price>
<currency>USD</currency>
<value>500.00</value>
</price>
</recurringPrice>
</recurring>
<usages/>
</finalPhase>
<plansAllowedInBundle>-1</plansAllowedInBundle>
</plan>
<plan name="standard-monthly" prettyName="standard-monthly">
<product>Standard</product>
<recurringBillingMode>IN_ADVANCE</recurringBillingMode>
<initialPhases>
<phase type="TRIAL">
<duration>
<unit>DAYS</unit>
<number>30</number>
</duration>
<fixed type="ONE_TIME">
<fixedPrice/>
</fixed>
<usages/>
</phase>
</initialPhases>
<finalPhase type="EVERGREEN">
<duration>
<unit>UNLIMITED</unit>
<number>-1</number>
</duration>
<recurring>
<billingPeriod>MONTHLY</billingPeriod>
<recurringPrice>
<price>
<currency>GBP</currency>
<value>75.00</value>
</price>
<price>
<currency>USD</currency>
<value>100.00</value>
</price>
</recurringPrice>
</recurring>
<usages/>
</finalPhase>
<plansAllowedInBundle>-1</plansAllowedInBundle>
</plan>
<plan name="super-monthly" prettyName="super-monthly">
<product>Super</product>
<recurringBillingMode>IN_ADVANCE</recurringBillingMode>
<initialPhases>
<phase type="TRIAL">
<duration>
<unit>DAYS</unit>
<number>30</number>
</duration>
<fixed type="ONE_TIME">
<fixedPrice/>
</fixed>
<usages/>
</phase>
</initialPhases>
<finalPhase type="EVERGREEN">
<duration>
<unit>UNLIMITED</unit>
<number>-1</number>
</duration>
<recurring>
<billingPeriod>MONTHLY</billingPeriod>
<recurringPrice>
<price>
<currency>GBP</currency>
<value>750.00</value>
</price>
<price>
<currency>USD</currency>
<value>1000.00</value>
</price>
</recurringPrice>
</recurring>
<usages/>
</finalPhase>
<plansAllowedInBundle>-1</plansAllowedInBundle>
</plan>
</plans>
<priceLists>
<defaultPriceList name="DEFAULT">
<plans>
<plan>basic-annual</plan>
<plan>sports-monthly</plan>
<plan>standard-monthly</plan>
<plan>super-monthly</plan>
</plans>
</defaultPriceList>
</priceLists>
</version>
</versions>
<catalogName>SpyCarBasic</catalogName>
</catalogs>
Query Parameters
Name | Type | Required | Default | Description |
---|---|---|---|---|
requestedDate | string | false | current date | requested date |
accountId | UUID | false | none | Account Id for which to fetch the catalog (applicable only in case of catalog plugins) |
Response
If successful, returns a status code of 200 and the catalog for the requested date in XML format.
Retrieve the catalog as JSON
This endpoint retrieves the Catalog for a requested date in JSON format. If there are multiple versions, the latest version with an effective date not later than the requested date is returned. If the effective date for all versions is greater than the requested date, the earliest version is returned. See the previous endpoint for examples.
HTTP Request
GET http://127.0.0.1:8080/1.0/kb/catalog
Example Request:
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Accept: application/json" \
"http://127.0.0.1:8080/1.0/kb/catalog"
import org.joda.time.DateTime;
import org.killbill.billing.client.api.gen.CatalogApi;
import org.killbill.billing.client.model.Catalogs;
protected CatalogApi catalogApi;
DateTime requestedDate = null;
UUID accountId = null;
Catalogs catalogsJson = catalogApi.getCatalogJson(requestedDate,
accountId,
requestOptions);
catalog = KillBillClient::Model::Catalog
requested_date = nil
catalog_json = catalog.get_tenant_catalog_json(requested_date,options)
catalogApi = killbill.CatalogApi()
catalog_json = catalogApi.get_catalog_json()
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const catalogJson: AxiosResponse<killbill.Catalog[], any> = await catalogApi.getCatalogJson();
$apiInstance = $client->getCatalogApi();
$catalogJson = $apiInstance->getCatalogJson();
Example Response:
[
{
"name": "SpyCarBasic",
"effectiveDate": "2013-02-08T00:00:00.000+0000",
"currencies": [
"USD",
"GBP"
],
"units": [],
"products": [
{
"type": "ADD_ON",
"name": "Super",
"prettyName": "Super",
"plans": [
{
"name": "super-monthly",
"prettyName": "super-monthly",
"billingPeriod": "MONTHLY",
"phases": [
{
"type": "TRIAL",
"prices": [],
"fixedPrices": [],
"duration": {
"unit": "DAYS",
"number": 30
},
"usages": []
},
{
"type": "EVERGREEN",
"prices": [
{
"currency": "GBP",
"value": 750
},
{
"currency": "USD",
"value": 1000
}
],
"fixedPrices": [],
"duration": {
"unit": "UNLIMITED",
"number": -1
},
"usages": []
}
]
}
],
"included": [],
"available": []
},
{
"type": "BASE",
"name": "Standard",
"prettyName": "Standard",
"plans": [
{
"name": "standard-monthly",
"prettyName": "standard-monthly",
"billingPeriod": "MONTHLY",
"phases": [
{
"type": "TRIAL",
"prices": [],
"fixedPrices": [],
"duration": {
"unit": "DAYS",
"number": 30
},
"usages": []
},
{
"type": "EVERGREEN",
"prices": [
{
"currency": "GBP",
"value": 75
},
{
"currency": "USD",
"value": 100
}
],
"fixedPrices": [],
"duration": {
"unit": "UNLIMITED",
"number": -1
},
"usages": []
}
]
}
],
"included": [],
"available": []
},
{
"type": "BASE",
"name": "Sports",
"prettyName": "Sports",
"plans": [
{
"name": "sports-monthly",
"prettyName": "sports-monthly",
"billingPeriod": "MONTHLY",
"phases": [
{
"type": "TRIAL",
"prices": [],
"fixedPrices": [],
"duration": {
"unit": "DAYS",
"number": 30
},
"usages": []
},
{
"type": "EVERGREEN",
"prices": [
{
"currency": "GBP",
"value": 375
},
{
"currency": "USD",
"value": 500
}
],
"fixedPrices": [],
"duration": {
"unit": "UNLIMITED",
"number": -1
},
"usages": []
}
]
}
],
"included": [],
"available": []
}
],
"priceLists": [
{
"name": "DEFAULT",
"plans": [
"sports-monthly",
"standard-monthly",
"super-monthly"
]
}
]
}
]
Query Parameters
Name | Type | Required | Default | Description |
---|---|---|---|---|
requestedDate | string | false | current date | requested date |
accountId | UUID | false | none | Account Id for which to fetch the catalog (applicable only in case of catalog plugins). |
Response
if successful, returns a status code of 200 and the full catalog for the requested date in JSON format.
Retrieve a list of catalog versions
Return a list of the effective dates for all available catalogs versions for this tenant.
HTTP Request
GET http://127.0.0.1:8080/1.0/kb/catalog/versions
Example Request:
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "accept: application/json" \
"http://127.0.0.1:8080/1.0/kb/catalog/versions"
import org.killbill.billing.client.api.gen.CatalogApi;
protected CatalogApi catalogApi;
UUID accountId = null;
List<DateTime> versions = catalogApi.getCatalogVersions(accountId, requestOptions);
catalog = KillBillClient::Model::Catalog
catalog_versions = catalog.get_tenant_catalog_versions(options)
catalogApi = killbill.CatalogApi()
catalog_versions = catalogApi.get_catalog_versions()
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const catalogVersions: AxiosResponse<string[], any> = await catalogApi.getCatalogVersions();
$apiInstance = $client->getCatalogApi();
$catalogVersions = $apiInstance->getCatalogVersions();
Example Response:
[
"2013-02-08T00:00:00.000Z"
]
Query Parameters
Name | Type | Required | Default | Description |
---|---|---|---|---|
accountId | UUID | false | none | Account Id for which to fetch the catalog (applicable only in case of catalog plugins). |
Response
If successful, returns a status code of 200 and a comma-separated list of ISO date strings giving the effective date for each available catalog version.
Retrieve available base plans
Returns a list of available base products and associated plans. Each object returned specifies a product
, a priceList
, a plan
selected from the pricelist
, and pricing information for the final phase of the plan.
HTTP Request
GET http://127.0.0.1:8080/1.0/kb/catalog/availableBasePlans
Example Request:
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Accept: application/json" \
"http://127.0.0.1:8080/1.0/kb/catalog/availableBasePlans"
import org.killbill.billing.client.api.gen.CatalogApi;
import org.killbill.billing.client.model.gen.PlanDetail;
protected CatalogApi catalogApi;
UUID accountId = null;
List<PlanDetail> basePlans = catalogApi.getAvailableBasePlans(accountId, requestOptions);
catalog = KillBillClient::Model::Catalog
available_base_plans = catalog.available_base_plans(options)
catalogApi = killbill.CatalogApi()
available_base_plans = catalogApi.get_available_base_plans()
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const availableBasePlans: AxiosResponse<killbill.PlanDetail[], any> = await catalogApi.getAvailableBasePlans();
$apiInstance = $client->getCatalogApi();
$availableBasePlans = $apiInstance->getAvailableBasePlans();
Example Response:
[
{
"product": "Sports",
"plan": "sports-monthly",
"priceList": "DEFAULT",
"finalPhaseBillingPeriod": "MONTHLY",
"finalPhaseRecurringPrice": [
{
"currency": "GBP",
"value": 375
},
{
"currency": "USD",
"value": 500
}
]
},
{
"product": "Standard",
"plan": "standard-monthly",
"priceList": "DEFAULT",
"finalPhaseBillingPeriod": "MONTHLY",
"finalPhaseRecurringPrice": [
{
"currency": "GBP",
"value": 75
},
{
"currency": "USD",
"value": 100
}
]
}
]
Query Parameters
Name | Type | Required | Default | Description |
---|---|---|---|---|
accountId | UUID | false | none | Account Id for which to fetch the catalog (applicable only in case of catalog plugins). |
Response
If successful, returns a status code of 200 and a list of objects representing the available base products and plans.
Retrieve available add-ons for a given product
Returns a list of available add-on products, if any, for a specified base product, and for a specified price list or all price lists. Each object returned specifies a product
, a priceList
, a plan
selected from the pricelist
, and pricing information for the final phase of the plan.
HTTP Request
GET http://127.0.0.1:8080/1.0/kb/catalog/availableAddons
Example Request:
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Accept: application/json" \
"http://127.0.0.1:8080/1.0/kb/catalog/availableAddons"
import org.killbill.billing.client.api.gen.CatalogApi;
import org.killbill.billing.client.model.gen.PlanDetail;
protected CatalogApi catalogApi;
String baseProductName = "Bullets";
String priceListName = null;
UUID accountId = null;
List<PlanDetail> availableAddons = catalogApi.getAvailableAddons(baseProductName,
priceListName,
accountId,
requestOptions);
catalog = KillBillClient::Model::Catalog
base_product_name = 'Standard'
available_addons = catalog.available_addons(base_product_name,
options)
catalogApi = killbill.CatalogApi()
available_add_on_plans = catalogApi.get_available_addons(base_product_name='Basic')
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const availableAddOns: AxiosResponse<killbill.PlanDetail[], any> = await catalogApi.getAvailableAddons();
$apiInstance = $client->getCatalogApi();
$baseProductName = 'Standard';
$availableAddOns = $apiInstance->getAvailableAddons($baseProductName);
Example Response:
[
{
"product":"Basic",
"plan":"basic-annual",
"finalPhaseBillingPeriod":"ANNUAL",
"priceList":"DEFAULT",
"finalPhaseRecurringPrice":[
{
"currency":"USD",
"value":10000.0
}
]
}
]
Query Parameters
Name | Type | Required | Default | Description |
---|---|---|---|---|
baseProductName | string | true | none | base product name |
priceListName | string | false | all price lists | price list name |
accountId | UUID | false | none | Account Id for which to fetch the catalog (applicable only in case of catalog plugins). |
Response
If successful, returns a status code of 200 and a list of objects representing available add-on products.
Delete all versions of a per tenant catalog
Delete all per-tenant catalog versions. The tenant reverts to the system default catalog.
HTTP Request
DELETE http://127.0.0.1:8080/1.0/kb/catalog
Example Request:
curl -v \
-X DELETE \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "X-Killbill-CreatedBy: demo" \
-H "X-Killbill-Reason: demo" \
-H "X-Killbill-Comment: demo" \
"http://127.0.0.1:8080/1.0/kb/catalog"
import org.killbill.billing.client.api.gen.CatalogApi;
protected CatalogApi catalogApi;
catalogApi.deleteCatalog(requestOptions);
catalog = KillBillClient::Model::Catalog
catalog.delete_catalog(user,reason,comment,options)
catalogApi = killbill.CatalogApi()
catalogApi.delete_catalog(created_by='demo',
reason='reason',
comment='comment')
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const response: AxiosResponse<any> = await catalogApi.deleteCatalog('created_by');
$apiInstance = $client->getCatalogApi();
$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";
$apiInstance->deleteCatalog($xKillbillCreatedBy,$xKillbillReason,$xKillbillComment);
Query Parameters
None.
Response
If successful, returns a a status code of 204 and an empty body.
Validate a catalog XML
This endpoint validates an XML catalog.
Following are some of the errors that can be detected via this endpoint:
- Catalog name does not match the name of the existing catalog
- A catalog with the particular effectiveDate already exists
- An EVERGREEN phase does not have duration as UNLIMITED
HTTP Request
POST http://127.0.0.1:8080/1.0/kb/catalog/xml/validate
Example Request:
curl -v \
-X POST \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Content-Type: text/xml" \
-H "Accept: application/json" \
-H "X-Killbill-CreatedBy: demo" \
-H "X-Killbill-Reason: demo" \
-H "X-Killbill-Comment: demo" \
-d @<path_to_catalog_xml> \
"http://127.0.0.1:8080/1.0/kb/catalog/xml/validate"
import java.nio.file.Files;
import java.nio.file.Path;
import org.killbill.billing.client.api.gen.CatalogApi;
import org.killbill.billing.client.model.gen.CatalogValidation;
import org.killbill.billing.client.model.gen.CatalogValidationError;
protected CatalogApi catalogApi;
CatalogValidation validation = catalogApi.validateCatalogXml(body, requestOptions);
List<CatalogValidationError> errors = validation.getCatalogValidationErrors();
user = 'user'
reason = 'reason'
comment = 'comment'
catalog = KillBillClient::Model::Catalog
catalog_file_xml = File.read("H:/killbill/catalog.xml")
errors = catalog.validate_catalog(catalog_file_xml,
user,
reason,
comment,
options)
catalogApi = killbill.CatalogApi()
xml_catalog = open("H:/killbill/catalog.xml", "r+").read()
catalog_validation_errors = catalogApi.validate_catalog_xml(xml_catalog,
created_by='demo',
reason='reason',
comment='comment')
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const fs = require('fs');
const body = fs.readFileSync('H:/killbill/catalog.xml').toString();
const catalogValidationErrors: AxiosResponse<killbill.CatalogValidation, any> = await catalogApi.validateCatalogXml(body,'created_by');
$apiInstance = $client->getCatalogApi();
$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";
$filename = "H:/killbill/catalog.xml";
$fileContents = file_get_contents($filename);
$catalogValidationErrors = $apiInstance->validateCatalogXml($fileContents,$xKillbillCreatedBy,$xKillbillReason,$xKillbillComment);
Example Response:
{
"catalogValidationErrors": [
{
"errorDescription": "Catalog name 'ExampleCatalog' is different from existing catalog name 'Firearms'"
}
]
}
Request Body
The complete catalog in XML format. Alternative, the path to the catalog XML file can also be specified.
Query Parameters
None.
Response
If successful, returns a status code of 200 and a CatalogValidation
object. If validation is successful and there are no validation errors, the CatalogValidation
object is empty, otherwise it contains a CatalogValidationError
List.
Subscription info
These endpoints return information concerning a particular subscription. They select from the catalog only the items (such as plan, phase, or products) that currently apply to the specified subscription.
Retrieve the phase for a given subscription and date
This API returns information about the current Phase
associated with a given subscription. The record returned includes the phase type and information about pricing, duration, and usage.
HTTP Request
GET http://127.0.0.1:8080/1.0/kb/catalog/phase
Example Request:
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Accept: application/json" \
"http://127.0.0.1:8080/1.0/kb/catalog/phase?subscriptionId=8ab101b6-15e8-433b-b4f7-f99eeaa56a77&requestedDate=2018-7-18"
import org.joda.time.LocalDate;
import org.killbill.billing.client.api.gen.CatalogApi;
import org.killbill.billing.client.model.gen.Phase;
protected CatalogApi catalogApi;
UUID subscriptionId = UUID.fromString("4c3fd23c-7b15-4acc-811e-fe92ee7fdffd");
LocalDate requestedDate = null;
Phase phase = catalogApi.getPhaseForSubscriptionAndDate(subscriptionId, requestedDate, requestOptions);
catalog = KillBillClient::Model::Catalog
requested_date = nil
subscription_id = 'dc99644c-04a3-49b3-9abc-6e94cffc7e60'
phase = catalog.get_catalog_phase(subscription_id,
requested_date,
options)
catalogApi = killbill.CatalogApi()
subscription_id = 'ad924bca-00f4-4287-82c2-e2932a5f7371'
phase = catalogApi.get_phase_for_subscription_and_date(subscription_id=subscription_id)
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const subscriptionId = 'ad924bca-00f4-4287-82c2-e2932a5f7371';
const phase: AxiosResponse<killbill.Phase, any> = await catalogApi.getPhaseForSubscriptionAndDate(subscriptionId);
$apiInstance = $client->getCatalogApi();
$subscriptionId = 'd28b70f8-6bc7-4cde-b21f-eaf723e146fc';
$phase = $apiInstance->getPhaseForSubscriptionAndDate($subscriptionId);
Example Response:
{
"type": "TRIAL",
"prices": [],
"fixedPrices": [],
"duration": {
"unit": "DAYS",
"number": 30
},
"usages": []
}
Query Parameters
Name | Type | Required | Default | Description |
---|---|---|---|---|
subscriptionId | string | true | none | subscription id |
requestedDate | string | false | current date | requested date |
Response
If successful, returns a status code of 200 and a record for the current phase.
Retrieve the plan for a given subscription and date
This API returns information about the current Plan
associated with a given subscription. The record returned includes the plan name and information for each phase of the plan.
HTTP Request
GET http://127.0.0.1:8080/1.0/kb/catalog/plan
Example Request:
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Accept: application/json" \
"http://127.0.0.1:8080/1.0/kb/catalog/plan?subscriptionId=8ab101b6-15e8-433b-b4f7-f99eeaa56a77&requestedDate=2018-7-18"
import org.joda.time.LocalDate;
import org.killbill.billing.client.api.gen.CatalogApi;
import org.killbill.billing.client.model.gen.Plan;
protected CatalogApi catalogApi;
UUID subscriptionId = UUID.fromString("4c3fd23c-7b15-4acc-811e-fe92ee7fdffd");
LocalDate requestedDate = null;
Plan plan = catalogApi.getPlanForSubscriptionAndDate(subscriptionId, requestedDate, requestOptions);
catalog = KillBillClient::Model::Catalog
requested_date = nil
subscription_id = 'dc99644c-04a3-49b3-9abc-6e94cffc7e60'
plan = catalog.get_catalog_plan(subscription_id,
requested_date,
options)
catalogApi = killbill.CatalogApi()
subscription_id = 'ad924bca-00f4-4287-82c2-e2932a5f7371'
plan = catalogApi.get_plan_for_subscription_and_date(subscription_id=subscription_id)
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const subscriptionId = 'ad924bca-00f4-4287-82c2-e2932a5f7371';
const plan: AxiosResponse<killbill.Plan, any> = await catalogApi.getPlanForSubscriptionAndDate(subscriptionId);
$apiInstance = $client->getCatalogApi();
$subscriptionId = 'd28b70f8-6bc7-4cde-b21f-eaf723e146fc';
$plan = $apiInstance->getPlanForSubscriptionAndDate($subscriptionId);
Example Response:
{
"name": "standard-monthly",
"prettyName": "standard-monthly",
"billingPeriod": "MONTHLY",
"phases": [
{
"type": "TRIAL",
"prices": [],
"fixedPrices": [],
"duration": {
"unit": "DAYS",
"number": 30
},
"usages": []
},
{
"type": "EVERGREEN",
"prices": [
{
"currency": "GBP",
"value": 75
},
{
"currency": "USD",
"value": 100
}
],
"fixedPrices": [],
"duration": {
"unit": "UNLIMITED",
"number": -1
},
"usages": []
}
]
}
Query Parameters
Name | Type | Required | Default | Description |
---|---|---|---|---|
subscriptionId | string | true | none | subscription id |
requestedDate | string | false | current date | requested date |
Response
If successful, returns a status code of 200 and a record for the plan for this subscription.
Retrieve the priceList for a given subscription and date
This API returns information about the current priceList
associated with a given subscription. The record returned includes the price list name and the list of plans on this list.
HTTP Request
GET http://127.0.0.1:8080/1.0/kb/catalog/priceList
Example Request:
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Accept: application/json" \
"http://127.0.0.1:8080/1.0/kb/catalog/priceList?subscriptionId=8ab101b6-15e8-433b-b4f7-f99eeaa56a77&requestedDate=2018-7-18"
import org.joda.time.LocalDate;
import org.killbill.billing.client.api.gen.CatalogApi;
import org.killbill.billing.client.model.gen.PriceList;
protected CatalogApi catalogApi;
UUID subscriptionId = UUID.fromString("4c3fd23c-7b15-4acc-811e-fe92ee7fdffd");
LocalDate requestedDate = null;
PriceList priceList = catalogApi.getPriceListForSubscriptionAndDate(subscriptionId, requestedDate,requestOptions);
catalog = KillBillClient::Model::Catalog
requested_date = nil
subscription_id = 'dc99644c-04a3-49b3-9abc-6e94cffc7e60'
price_list = catalog.get_catalog_price_list(subscription_id,
requested_date,
options)
catalogApi = killbill.CatalogApi()
subscription_id = 'ad924bca-00f4-4287-82c2-e2932a5f7371'
price_list = catalogApi.get_price_list_for_subscription_and_date(subscription_id=subscription_id)
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const subscriptionId = 'ad924bca-00f4-4287-82c2-e2932a5f7371';
const priceList: AxiosResponse<killbill.PriceList, any> = await catalogApi.getPriceListForSubscriptionAndDate(subscriptionId);
$apiInstance = $client->getCatalogApi();
$subscriptionId = 'd28b70f8-6bc7-4cde-b21f-eaf723e146fc';
$priceList = $apiInstance->getPriceListForSubscriptionAndDate($subscriptionId);
Example Response:
{
"name": "DEFAULT",
"plans": [
"sports-monthly",
"standard-monthly",
"super-monthly"
]
}
Query Parameters
Name | Type | Required | Default | Description |
---|---|---|---|---|
subscriptionId | string | true | none | subscription id |
requestedDate | string | false | current date | requested date |
Response
If successful, returns a status code of 200 and a record for the price list for this subscription.
Retrieve product for a given subscription and date
This API returns information about the product
associated with a given subscription. The record returned includes the product names, available plans, items included, and available add-ons.
HTTP Request
GET http://127.0.0.1:8080/1.0/kb/catalog/product
Example Request:
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Accept: application/json" \
"http://127.0.0.1:8080/1.0/kb/catalog/product?subscriptionId=8ab101b6-15e8-433b-b4f7-f99eeaa56a77&requestedDate=2018-7-18"
import org.joda.time.LocalDate;
import org.killbill.billing.client.api.gen.CatalogApi;
import org.killbill.billing.client.model.gen.Product;
protected CatalogApi catalogApi;
UUID subscriptionId = UUID.fromString("4c3fd23c-7b15-4acc-811e-fe92ee7fdffd");
LocalDate requestedDate = null;
Product product = catalogApi.getProductForSubscriptionAndDate(subscriptionId, requestedDate,requestOptions);
catalog = KillBillClient::Model::Catalog
requested_date = nil
subscription_id = 'dc99644c-04a3-49b3-9abc-6e94cffc7e60'
product = catalog.get_catalog_product(subscription_id,
requested_date,
options)
catalogApi = killbill.CatalogApi()
subscription_id = 'ad924bca-00f4-4287-82c2-e2932a5f7371'
product = catalogApi.get_product_for_subscription_and_date(subscription_id=subscription_id)
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const subscriptionId = 'ad924bca-00f4-4287-82c2-e2932a5f7371';
const product: AxiosResponse<killbill.Product, any> = await catalogApi.getProductForSubscriptionAndDate(subscriptionId);
$apiInstance = $client->getCatalogApi();
$subscriptionId = 'd28b70f8-6bc7-4cde-b21f-eaf723e146fc';
$product = $apiInstance->getProductForSubscriptionAndDate($subscriptionId);
Example Response:
{
"type": "BASE",
"name": "Standard",
"prettyName": "Standard",
"plans": [],
"included": [],
"available": []
}
Query Parameters
Name | Type | Required | Default | Description |
---|---|---|---|---|
subscriptionId | string | true | none | subscription id |
requestedDate | string | false | current date | requested date |
Response
If successful, returns a status code of 200 and a record for the product for this subscription.
Simple Plan
We provide a more basic level of APIs as a quick way to add a Plan
into an existing version of the catalog.
The intent is mostly to help getting started with Kill Bill by abstracting away more complex topics such as alignements, rules, ...
The functionality is exposed on our admin UI (KAUI) to provide a simple graphical way to configure a simple catalog and get started quickly.
One can directly use our Simple Plan API to add new Plans
without the need to create an initial catalog version: If there is no
existing catalog version for the tenant, the system will create such an initial version when the first plan is added; otherwise, the
system will use the existing active catalog version to add the new plan (but it will not create a new catalog version).
Note that because the Simple Plan API is just an abstraction on top of the more complex XML based APIs, one can start with such Simple Plan API, and then download the resulting XML, and edit such catalog by hand (to add entries, modify default rules, ...).
A simple plan has the following limitations:
- In-advance billing only
- Limited to one
RECURRING
phase and an optional $0TRIAL
phase - No suport for fixed price
Once a simple plan has been uploaded, one can retrieve the associated XML, edit it to configure additional aspects, and then upload a new version of this catalog. So, this functionality can also be a stepping stone to a full catalog configuration.
Add a simple plan
Add a (simple) Plan into the current version of the Catalog associated with the tenant.
HTTP Request
POST http://127.0.0.1:8080/1.0/kb/catalog/simplePlan
Example Request:
curl -v \
-X POST \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "X-Killbill-CreatedBy: demo" \
-H "X-Killbill-Reason: demo" \
-H "X-Killbill-Comment: demo" \
-d '{ "planId": "basic-annual", "productName": "Basic", "productCategory": "BASE", "currency": "USD", "amount": 1000, "billingPeriod": "ANNUAL", "trialLength": 0, "trialTimeUnit": "UNLIMITED"}' \
"http://localhost:8080/1.0/kb/catalog/simplePlan"
import java.math.BigDecimal;
import java.util.Collections;
import org.killbill.billing.client.api.gen.CatalogApi;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.catalog.api.TimeUnit;
import org.killbill.billing.client.model.gen.SimplePlan;
protected CatalogApi catalogApi;
String planId = "foo-monthly";
String productName = "Foo";
Integer trialLength = 0;
SimplePlan body = new SimplePlan(planId,
productName,
ProductCategory.BASE,
Currency.USD,
BigDecimal.TEN,
BillingPeriod.MONTHLY,
trialLength,
TimeUnit.UNLIMITED,
Collections.emptyList());
catalogApi.addSimplePlan(body, requestOptions);
user = 'user'
reason = 'reason'
comment = 'comment'
catalog = KillBillClient::Model::Catalog
simple_plan = KillBillClient::Model::SimplePlanAttributes.new
simple_plan.plan_id = 'basic-annual'
simple_plan.product_name = 'Basic'
simple_plan.product_category = 'BASE'
simple_plan.currency = 'USD'
simple_plan.amount = 10000.00
simple_plan.billing_period = 'ANNUAL'
simple_plan.trial_length = 0
simple_plan.trial_time_unit = 'UNLIMITED'
catalog.add_tenant_catalog_simple_plan(simple_plan,
user,
reason,
comment,
options)
catalogApi = killbill.CatalogApi()
body = killbill.SimplePlan(plan_id='basic-annual',
product_name='Basic',
product_category='BASE',
currency='USD',
amount=10000.00,
billing_period='ANNUAL',
trial_length=0,
trial_time_unit='UNLIMITED')
catalogApi.add_simple_plan(body,
created_by='demo',
reason='reason',
comment='comment')
const catalogApi: killbill.CatalogApi = new killbill.CatalogApi(config);
const simplePlan: killbill.SimplePlan = {
planId: 'basic-annual',
productName: 'Basic',
productCategory: 'BASE',
currency: 'USD',
amount: 10000,
billingPeriod: 'ANNUAL',
trialLength: 0,
trialTimeUnit: 'UNLIMITED'
};
const response: AxiosResponse<string, any> = await catalogApi.addSimplePlan(simplePlan,
'created_by');
$apiInstance = $client->getCatalogApi();
$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";
$simplePlan = new SimplePlan();
$simplePlan->setPlanId('basic-annual');
$simplePlan->setProductName('Basic');
$simplePlan->setProductCategory('BASE');
$simplePlan->setCurrency('USD');
$simplePlan->setAmount(10000);
$simplePlan->setBillingPeriod('ANNUAL');
$simplePlan->setTrialLength(0);
$simplePlan->setTrialTimeUnit('UNLIMITED');
$apiInstance->addSimplePlan($simplePlan,$xKillbillCreatedBy,$xKillbillReason,$xKillbillComment);
Request Body
Provides the content for the plan in JSON form. This should be very simple. Note that the "planId" becomes the planName
attribute. For example:
{
"planId": "newplan",
"productName": "myitem",
"productCategory": "BASE",
"currency": "USD",
"amount": 0,
"billingPeriod": "DAILY",
"trialLength": 0,
"trialTimeUnit": "DAYS",
"availableBaseProducts": []
}
Query Parameters
None.
Response
If successful, returns a status code of 201 and an empty body.