Subscription

A Subscription in Kill Bill entitles a customer to the use of a product or service for a period of time in exchange for a specified payment. Every subscription belongs to a Bundle that is associated with a given customer Account.

Subscriptions are created by specifying a Plan from the catalog, and an effective date on which to start. The Plan identifies the Product subscribed along with the terms of service and of billing. These attributes are used by the system to drive the generation of invoices. Kill Bill offers two parallel views of the subscription: one to track the entitlement, i.e the service associated with the subscription, and one to track the billing. These views address the following questions:

For most use cases, those two views are one and the same; the customer gets invoiced for what she consumes.

Please refer to our subscription manual for more details.

Subscription Resource

The Subscription resource represents a subscription. The attributes contained in the subscription resource are the following:

Name Type Generated by Description
accountId string system UUID for the account
bundleId string system UUID for the bundle
subscriptionId string system UUID for this subscription
externalKey string user Optional external key for the subscription
bundleExternalKey string user Optional external key for the bundle
startDate date user Datetime the service (entitlement) starts
productName string user Name of the product subscribed (from catalog)
productCategory string user Product catgory (see notes below)
billingPeriod string user Billing period (see notes below)
phaseType string user Type of the current plan phase (see notes below)
priceList string user Name of the current price list (from catalog)
planName string user Name of the current plan (from catalog)
state string system Current state of the subscription (see notes below)
sourceType string system Kind of subscription (see notes below)
cancelledDate date user Datetime when the service stopped, or will stop
chargedThroughDate date system Date up to which the subscription has been invoiced (see notes below)
billingStartDate date user Datetime on which the system starts invoicing
billingEndDate date user Datetime on which the system ends invoicing
billCycleDayLocal integer user or system Day of the month on which invoices are generated, if applicable (see notes below)
events list system List of subscription events corresponding to this subscription. See SubscriptionEvent resource below.
prices list user list of prices, one for each phase in the plan
priceOverrides list user list of prices if this subscription has price overrides (see notes below)
quantity integer user quantity of subscriptions (see notes below)
auditlogs array system Array of audit log records for this invoice

productCategory: possible values are BASE, ADD_ON, or STANDALONE

billingPeriod: possible values are DAILY, WEEKLY, BIWEEKLY, THIRTY_DAYS, THIRTY_ONE_DAYS, SIXTY_DAYS, NINETY_DAYS, MONTHLY, BIMESTRIAL (bimonthly), QUARTERLY, TRIANNUAL, BIANNUAL, ANNUAL, SESQUIENNIAL, BIENNIAL, TRIENNIAL, or NO_BILLING_PERIOD

phaseType: possible values are: TRIAL, DISCOUNT, FIXEDTERM, or EVERGREEN

state: possible values are:

sourceType: possible values are NATIVE, MIGRATED, or TRANSFERRED

chargedThroughDate: The date up to which the entitlement for this subscription has been invoiced. For IN_ADVANCE billing mode, this date will often be in the future; for IN_ARREAR, this date will often be in the past. For example,

  1. A subscription is billed each month, on the 15th, in advance. If we check on May 31, the chargedThroughDate will be June 15th, 15 days ahead. If the subscription is ended on May 31, a prorated credit will need to be issued.

  2. A subscription is billed quarterly, in arrears, on the 10th of Feb., May, Aug., and Nov. If we check on Jul. 20, the chargedThroughDate will be May 10, over 2 months earlier. If the subscription is cancelled on Jul. 20, an additional invoice will need to be issued.

These use cases assume that invoicing is up to date. If AUTO_INVOICING_OFF is set, invoicing relies on a manual process and may be late. In that situation the first use case may require a smaller credit or none at all, while the second case will have a larger amount to be billed to close out the subscription.

billCycleDayLocal: this value is either the overridden subscription billCycleDay (in case of BCD change) or the value at the subscription, bundle or account level (depending on the catalog billing alignments). For ACCOUNT billing alignments, if the account level billCycleDay hasn't been set yet, the value returned would be null.

priceOverrides: List of overridden prices for specific plan phases. Can be specified to override the fixed/recurring price in the catalog for a particular phase. For example, suppose you are creating a subscription corresponding to a plan that has an EVERGREEN phase with a recurring price of $100. You can specify an overridden price of 200 while creating the subscription by specifying a priceOverrides object as follows:

"priceOverrides": [ { "planName": "shotgun-monthly", "phaseType": "DISCOUNT", "fixedPrice": null, "recurringPrice": 150.00, "usagePrices": [] }

quantity: An integer value that specifies the quantity of subscription. The default value is 1. The corresponding invoice is generated as per the quantity. So if price=$20/mo, quantity=$2 => invoiceItem recurring amount=$40.

SubscriptionEvent Resource

The SubscriptionEvent resource represents an event on a subscription. An event is generated when a subscription is created, cancelled, paused, resumed,etc. In addition, events are also generated when there is a phase change or plan change.

Name Type Generated by Description
eventId string system UUID for this subscription event
billingPeriod string user Billing period (see notes above)
effectiveDate DateTime system DateTime that the event is effective
catalogEffectiveDate DateTime user The effective date of the underlying catalog.
plan string user Name of the current plan (from catalog)
product date user Name of the product subscribed (from catalog)
priceList string user Name of the current price list (from catalog)
phase string user Name of the current phase (from catalog)
eventType string user Type of event (see notes below)
isBlockedBilling boolean user Boolean flag that indicates whether billing should be blocked
isBlockedEntitlement boolean user Boolean flag that indicates whether the entitlement should be blocked
serviceName string user Name of the service that inserts the event
serviceStateName string user Name of the event state

eventType: possible event types are START_ENTITLEMENT, START_BILLING, PAUSE_ENTITLEMENT, PAUSE_BILLING, RESUME_ENTITLEMENT, RESUME_BILLING, PHASE, CHANGE, STOP_ENTITLEMENT, STOP_BILLING, SERVICE_STATE_CHANGE. See also SubscriptionEventType.

Subscriptions

These endpoints support the basic CRUD operations on Subscriptions.

Create a subscription

This API creates a base product subscription. It also creates a bundle to contain the subscription. See Bundle for further information.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/subscriptions

Example Request:


# With planName
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '{ 
            "accountId": "581d86fc-7cfc-46f2-b6d4-4dbc1d98beb3",
            "externalKey": "somethingSpecial",
            "planName": "super-monthly"
        }' \
    "http://127.0.0.1:8080/1.0/kb/subscriptions" 

# With productName, productCategory and billingPeriod

    curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '{ 
          "accountId": "59afd9fe-e98d-4fb3-b5bf-21d4a2b036cd",
            "externalKey": "somethingSpecial", 
            "productName": "Test", 
            "productCategory": "BASE",  
            "billingPeriod": "MONTHLY",
            "priceList": "DEFAULT"
        }' \
    "http://127.0.0.1:8080/1.0/kb/subscriptions"    

# With priceOverrides

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '{ 
            "accountId": "944bf633-88a8-4575-96b5-80bf0a0fdfec",
            "planName": "pistol-monthly-notrial",
             "priceOverrides": [

        {
            "planName": "pistol-monthly-notrial",
            "phaseType": "EVERGREEN",
            "fixedPrice": null,
            "recurringPrice": 400.00,
            "usagePrices": []
        }       
    ]
        }' \
    "http://127.0.0.1:8080/1.0/kb/subscriptions"

# With Datetime

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '{ 
            "accountId": "325fbe1c-7c35-4d96-a4e5-2cbaabe218c6",
            "planName": "pistol-monthly-notrial"
        }' \
    "http://127.0.0.1:8080/1.0/kb/subscriptions?billingDate=2023-02-07T11:15&entitlementDate=2023-02-07T11:15" 

import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID accountId = UUID.fromString("905a0636-ab63-40c0-acd4-b461b6808b5d");

Subscription input = new Subscription();
input.setAccountId(accountId);
input.setExternalKey("somethingSpecial");
input.setPlanName("shotgun-monthly");

LocalDate entitlementDate = null;
LocalDate billingDate = null;
Boolean renameKeyIfExistsAndUnused = null; 
Boolean migrated = null;
Boolean skipResponse = false;
Boolean callCompletion = true;
long DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC = 10;
Map<String, String> NULL_PLUGIN_PROPERTIES = null;

Subscription subscription = subscriptionApi.createSubscription(input, 
                                                               entitlementDate, 
                                                               billingDate, 
                                                               renameKeyIfExistsAndUnused, 
                                                               migrated,
                                                               skipResponse,  
                                                               callCompletion, 
                                                               DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, 
                                                               NULL_PLUGIN_PROPERTIES, 
                                                               requestOptions);
user = "demo"
reason = nil
comment = nil

subscription = KillBillClient::Model::Subscription.new
subscription.account_id = "e1826665-4524-4d57-81b5-a5eb11146f3f"
subscription.plan_name = "basic-monthly-in-advance"

requested_date  = nil
call_completion = nil 

subscription.create(user, 
                    reason, 
                    comment, 
                    requested_date, 
                    call_completion, 
                    options)
subscriptionApi = killbill.api.SubscriptionApi()

account_id = '32660591-b8a0-4a0e-b6a8-9b52611217c2'
body = Subscription(account_id=account_id, plan_name='pistol-monthly')

subscriptionApi.create_subscription(body, 
                                    created_by='demo',
                                    reason='reason', 
                                    comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscription: Subscription = {planName: "blowdart-monthly", accountId: "04779ade-11f9-48d1-88a1-a63be84d1cb7"};

api.createSubscription(subscription, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$body = new Subscription();
$body -> setAccountId('13102713-9672-4e3b-8b4f-e10869fc5a59');
$body -> setPlanName('pistol-monthly');

$entitlementDate = null;
$billingDate = null;
$renameKeyIfExistsAndUnused = false;
$migrated = false;
$skipResponse = false;
$callCompletion = false;
$callTimeoutSec = 3;
$pluginProperty = array("pluginProperty_example");

$result = $apiInstance->createSubscription($body, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment, $entitlementDate, $billingDate, $renameKeyIfExistsAndUnused, $migrated, $skipResponse, $callCompletion, $callTimeoutSec, $pluginProperty);

Request Body

A subscription resource object specifying accountId and either the planName or a combination of productName, productCategory,billingPeriod and priceList.

It can also include the following optional fields:

Query Parameters

Name Type Required Default Description
entitlementDate string no immediately Date/DateTime at which the entitlement (service) starts in yyyy-mm-dd/yyyy-mm-ddThh:mm format.
billingDate string no immediately Date/DateTime at which the entitlement (service) starts in yyyy-mm-dd/yyyy-mm-ddThh:mm format.
renameKeyIfExistsAndUnused boolean no true If true, rename external key if it exists and is unused
migrated boolean no false If true, subscription is migrated
skipResponse boolean no false TODO
callCompletion boolean no false see below
callTimeoutSec long no unlimited? Timeout in seconds (see below)

Creating a subscription often triggers the creation of an invoice, and associated with this there is often a payment (against the invoice). If callCompletion is true, the call to this API will be delayed until the invoice is created and/or the payment is processed. However, the maximum delay in seconds will be given by callTimeoutSec.

Other Notes:

Response

If successful, returns a status code of 201 and an empty body. In addition, a Location header is returned which contains the new subscription id.

Create a subscription with addon products

This API creates a subscription bundle with base and addon product subscriptions. It can also be used to add an addon subscription to a base subscription in which case the bundle id of the base subscription must be specified.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/subscriptions/createSubscriptionWithAddOns

Example Request:

# create a subscription with addon
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '[
          {
            "accountId": "581d86fc-7cfc-46f2-b6d4-4dbc1d98beb3",
            "externalKey": "something",
            "bundleExternalKey": "somethingAlso",
            "productName": "Sports",
            "productCategory": "BASE",
            "billingPeriod": "MONTHLY",
            "priceList": "DEFAULT"
        },
        {
          "accountId": "581d86fc-7cfc-46f2-b6d4-4dbc1d98beb3",
          "productName": "OilSlick",
          "productCategory": "ADD_ON",
          "billingPeriod": "MONTHLY",
          "priceList": "DEFAULT"
        }
        ]' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/createSubscriptionWithAddOns' 

OR

# create an addon on an existing base subscription
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '[

        {
          "accountId": "1f635c3d-fc24-4fa8-81e0-ab646882807a",
          "planName": "remotecontrol-monthly",
          "bundleId":"b4709feb-bd14-455a-bbb4-57a758498791"
        }
        ]' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/createSubscriptionWithAddOns'   

import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID accountId = UUID.fromString("abfba40d-d2dd-47f0-94f2-8ea3e6bc8794");

Subscription base = new Subscription();
base.setAccountId(accountId);
base.setExternalKey("base");
base.setProductName("Shotgun");
base.setProductCategory(ProductCategory.BASE);
base.setBillingPeriod(BillingPeriod.MONTHLY);
base.setPriceList("DEFAULT");

final Subscription addOn1 = new Subscription();
addOn1.setAccountId(accountId);
addOn1.setProductName("Telescopic-Scope");
addOn1.setProductCategory(ProductCategory.ADD_ON);
addOn1.setBillingPeriod(BillingPeriod.MONTHLY);
addOn1.setPriceList("DEFAULT");

final Subscription addOn2 = new Subscription();
addOn2.setAccountId(accountId);
addOn2.setProductName("Laser-Scope");
addOn2.setProductCategory(ProductCategory.ADD_ON);
addOn2.setBillingPeriod(BillingPeriod.MONTHLY);
addOn2.setPriceList("DEFAULT");

final Subscriptions subscriptions = new Subscriptions();
subscriptions.add(base);
subscriptions.add(addOn1);
subscriptions.add(addOn2);

LocalDate entitlementDate = null;
LocalDate billingDate = null;
Boolean migrated = null;
Boolean skipResponse = false;
Boolean renameKeyIfExistsAndUnused = null;
Boolean callCompletion = true;
long DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC = 10;
Map<String, String> NULL_PLUGIN_PROPERTIES = null;

final Bundle bundle = subscriptionApi.createSubscriptionWithAddOns(subscriptions, 
                                                                   entitlementDate, 
                                                                   billingDate, 
                                                                   migrated, 
                                                                   skipResponse,
                                                                   renameKeyIfExistsAndUnused, 
                                                                   callCompletion, 
                                                                   DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, 
                                                                   NULL_PLUGIN_PROPERTIES, 
                                                                   requestOptions);
user = "demo"
reason = nil
comment = nil

entitlement = [
                {
                    "accountId":"e3a23520-2ce2-493a-a3c0-7fc08e554353",
                    "productCategory":"BASE",
                    "productName":"Shotgun",
                    "billingPeriod":"MONTHLY",
                    "priceList":"DEFAULT"
                },
                {
                    "accountId":"e3a23520-2ce2-493a-a3c0-7fc08e554353",
                    "productCategory":"ADD_ON",
                    "productName":"Telescopic-Scope",
                    "billingPeriod":"MONTHLY",
                    "priceList":"DEFAULT"
                }
             ]

requested_date = nil
entitlement_date = nil
billing_date = nil
migrated = false
call_completion_sec = 3

subscription = KillBillClient::Model::Subscription.new
subscription.create_entitlement_with_add_on(entitlement,
                                            requested_date,
                                            entitlement_date,
                                            billing_date,
                                            migrated,
                                            call_completion_sec,
                                            user,
                                            reason,
                                            comment,
                                            options)
subscriptionApi = killbill.api.SubscriptionApi()

account_id = '32660591-b8a0-4a0e-b6a8-9b52611217c2'
subscription_a = Subscription(account_id=account_id,
                              plan_name='pistol-monthly')

subscription_b = Subscription(account_id=account_id,
                              plan_name='cleaning-monthly')

body = [subscription_a, subscription_b]

subscriptionApi.create_subscription_with_add_ons(body, 
                                                 created_by='demo', 
                                                 reason='reason', 
                                                 comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const base: Subscription = {planName: "pistol-monthly", accountId: "04779ade-11f9-48d1-88a1-a63be84d1cb7"};
const addon: Subscription = {planName: "cleaning-monthly", accountId: "04779ade-11f9-48d1-88a1-a63be84d1cb7"};
const subscriptions =[base, addon];

api.createSubscriptionWithAddOns(subscriptions, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$base = new Subscription();
$base -> setAccountId('13102713-9672-4e3b-8b4f-e10869fc5a59');
$base -> setPlanName('pistol-monthly');

$addon = new Subscription();
$addon -> setAccountId('13102713-9672-4e3b-8b4f-e10869fc5a59');
$addon -> setPlanName('cleaning-monthly');

$body = array($base, $addon);

$entitlementDate = null;
$billingDate = null;
$migrated = false;
$skipResponse = false;
$renameKeyIfExistsAndUnused = true;
$callCompletion = false;
$callTimeoutSec = 3;
$pluginProperty = array("pluginProperty_example");

$result = $apiInstance->createSubscriptionWithAddOns($body, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment, $entitlementDate, $billingDate, $migrated, $skipResponse, $renameKeyIfExistsAndUnused, $callCompletion, $callTimeoutSec, $pluginProperty);

Request Body

A subscription resource object corresponding to the base subscription and zero or more subscription resource objects corresponding to add-on subscriptions need to be specified. Alternatively, only a list of add-on subscription resource objects may be specified along with the base subscription bundle id. Each subscription resource object needs to include accountId and either the planName or a combination of productName, productCategory,billingPeriod and priceList.

In addition, each subscription resource can also include the following optional fields:

Query Parameters

Name Type Required Default Description
entitlementDate string no immediately Date at which the entitlement (sevice) starts in yyyy-mm-dd format. If specified, applies both to base and add-on products.
billingDate string no immediately Date at which the billing starts in yyyy-mm-dd format. If specified, applies both to base and add-on products.
renameKeyIfExistsAndUnused boolean no true If true, rename external key if it exists and is unused
migrated boolean no false If true, subscription is migrated
skipResponse boolean no false TODO
callCompletion boolean no false see below
callTimeoutSec long no unlimited? Timeout in seconds (see below)
pluginProperty array of strings false omit list of plugin properties, if any

Creating a subscription often triggers the creation of an invoice, and associated with this there is often a payment (against the invoice). If callCompletion is true, the call to this API will be delayed until the invoice is created and/or the payment is processed. However, the maximum delay in seconds will be given by callTimeoutSec.

Response

If successful, returns a status code of 201 and an empty body. In addition, a Location header is returned which contains the new bundle id.

Create multiple subscriptions with addon products

This API creates multiple subscriptions with base and addon product subscriptions. It can also be used to add an addon subscription to a base subscription in which case the bundle id of the base subscription must be specified.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/subscriptions/createSubscriptionsWithAddOns

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 "X-Killbill-CreatedBy: demo" \
    -d '[
          {
            "baseEntitlementAndAddOns": [
              {
                "accountId": "886adb60-be70-40c8-b97d-1f8ecbc30a64",
                "externalKey": "base",
                "productName": "Sports",
                "productCategory": "BASE",
                "billingPeriod": "MONTHLY",
                "priceList": "DEFAULT"
              },
              {
                "accountId": "886adb60-be70-40c8-b97d-1f8ecbc30a64",
                "productName": "OilSlick",
                "productCategory": "ADD_ON",
                "billingPeriod": "MONTHLY",
                "priceList": "DEFAULT"
              }
            ]
          },
           {
            "baseEntitlementAndAddOns": [
              {
                "accountId": "59afd9fe-e98d-4fb3-b5bf-21d4a2b036cd",
                "externalKey": "createSubscriptionsWithAddOns3",
                "productName": "Test",
                "productCategory": "BASE",
                "billingPeriod": "MONTHLY",
                "priceList": "DEFAULT"
              },
              {
                "accountId": "59afd9fe-e98d-4fb3-b5bf-21d4a2b036cd",
                "productName": "TestAO",
                "productCategory": "ADD_ON",
                "billingPeriod": "MONTHLY",
                "priceList": "DEFAULT"
              }
            ]
          }
        ]' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/createSubscriptionsWithAddOns' 

OR 

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '[
          {
            "baseEntitlementAndAddOns": [
              {
                "accountId": "1f635c3d-fc24-4fa8-81e0-ab646882807a",
                "planName": "remotecontrol-monthly",  
                "bundleId":"a8b4022c-e38c-4336-ad2f-ee15c5e18d12"
              }
            ]
          },
          {
            "baseEntitlementAndAddOns": [

              {
                "accountId": "1f635c3d-fc24-4fa8-81e0-ab646882807a",
                "planName": "remotecontrol-monthly",
                "bundleId":"06892885-c276-4cf9-8311-ef0b8a2e364b"
              }
            ]
          }
        ]' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/createSubscriptionsWithAddOns' 

import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID accountId = UUID.fromString("a3087bfb-eb81-466d-afeb-6501c30f8f85");

Subscription base = new Subscription();
base.setAccountId(accountId);
base.setPlanName("test-monthly");

final Subscription addOn1 = new Subscription();
addOn1.setAccountId(accountId);
addOn1.setPlanName("testao-monthly");

final Subscriptions subscriptions = new Subscriptions();
subscriptions.add(base);
subscriptions.add(addOn1);

BulkSubscriptionsBundle bulkSubscriptionsBundle = new BulkSubscriptionsBundle();
bulkSubscriptionsBundle.setBaseEntitlementAndAddOns(subscriptions);

Subscription base2 = new Subscription();
base2.setAccountId(accountId);
base2.setPlanName("product1-monthly");

Subscription base2addOn1 = new Subscription();
base2addOn1.setAccountId(accountId);
base2addOn1.setPlanName("product1-ao-monthly");

Subscriptions subscriptions2 = new Subscriptions();
subscriptions2.add(base2);
subscriptions2.add(base2addOn1);

BulkSubscriptionsBundle bulkSubscriptionsBundle2 = new BulkSubscriptionsBundle();
bulkSubscriptionsBundle2.setBaseEntitlementAndAddOns(subscriptions2);

BulkSubscriptionsBundles bulkSubscriptionsBundles = new BulkSubscriptionsBundles();
bulkSubscriptionsBundles.add(bulkSubscriptionsBundle);
bulkSubscriptionsBundles.add(bulkSubscriptionsBundle2);

LocalDate entitlementDate = null;
LocalDate billingDate = null;
Boolean renameKeyIfExistsAndUnused = false;
Boolean migrated = false;
Boolean skipResponse = false;
Boolean callCompletion = true;
long DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC = 10;
Map<String, String> NULL_PLUGIN_PROPERTIES = null;

Bundles bundles = subscriptionApi.createSubscriptionsWithAddOns(bulkSubscriptionsBundles, 
                                                                 entitlementDate, 
                                                                 billingDate, 
                                                                 renameKeyIfExistsAndUnused, 
                                                                 migrated, 
                                                                 skipResponse, 
                                                                 callCompletion, 
                                                                DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, NULL_PLUGIN_PROPERTIES,                                                               requestOptions);
user = "demo"
reason = nil
comment = nil

bulk_subscription_list = [
                            {
                               "baseEntitlementAndAddOns":[
                                  {
                                     "accountId":"e3a23520-2ce2-493a-a3c0-7fc08e554353",
                                     "productCategory":"BASE",
                                     "productName":"Pistol",
                                     "billingPeriod":"MONTHLY",
                                     "priceList":"DEFAULT"
                                  },
                                  {
                                     "accountId":"e3a23520-2ce2-493a-a3c0-7fc08e554353",
                                     "productCategory":"ADD_ON",
                                     "productName":"Cleaning",
                                     "billingPeriod":"MONTHLY",
                                     "priceList":"DEFAULT"
                                  }
                               ]
                            },
                            {
                               "baseEntitlementAndAddOns":[
                                  {
                                     "accountId":"e3a23520-2ce2-493a-a3c0-7fc08e554353",
                                     "productCategory":"BASE",
                                     "productName":"Shotgun",
                                     "billingPeriod":"MONTHLY",
                                     "priceList":"DEFAULT"
                                  },
                                  {
                                     "accountId":"e3a23520-2ce2-493a-a3c0-7fc08e554353",
                                     "productCategory":"ADD_ON",
                                     "productName":"Telescopic-Scope",
                                     "billingPeriod":"MONTHLY",
                                     "priceList":"DEFAULT"
                                  }
                               ]
                            },

                         ]
entitlement_date = nil
billing_date = nil
call_completion_sec = nil

KillBillClient::Model::BulkSubscription.create_bulk_subscriptions(bulk_subscription_list,
                                                                  user,
                                                                  reason,
                                                                  comment,
                                                                  entitlement_date,
                                                                  billing_date,
                                                                  call_completion_sec,
                                                                  options)
subscriptionApi = killbill.api.SubscriptionApi()

account_id = '32660591-b8a0-4a0e-b6a8-9b52611217c2'
subscription_a = Subscription(account_id=account_id,
                              plan_name='pistol-thirty-days')

subscription_b = Subscription(account_id=account_id,
                              plan_name='cleaning-monthly')

bundle1 = BulkSubscriptionsBundle([subscription_a, subscription_b])

subscription_c = Subscription(account_id=account_id,
                              plan_name='shotgun-monthly')

subscription_d = Subscription(account_id=account_id,
                              plan_name='holster-monthly-regular')

bundle2 = BulkSubscriptionsBundle([subscription_c, subscription_d])

subscriptionApi.create_subscriptions_with_add_ons([bundle1, bundle2],
                                                  created_by='demo',
                                                  reason='reason',
                                                  comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const base1: Subscription = {planName: "pistol-monthly", accountId: "04779ade-11f9-48d1-88a1-a63be84d1cb7"};
const addon1: Subscription = {planName: "cleaning-monthly", accountId: "04779ade-11f9-48d1-88a1-a63be84d1cb7"};
const subscriptions1 = [base1, addon1];
const bulkSubBundle1: BulkSubscriptionsBundle = {baseEntitlementAndAddOns: subscriptions1};

const base2: Subscription = {planName: "shotgun-monthly", accountId: "04779ade-11f9-48d1-88a1-a63be84d1cb7"};
const addon2: Subscription = {planName: "telescopic-scope-monthly", accountId: "04779ade-11f9-48d1-88a1-a63be84d1cb7"};
const subscriptions2 = [base2, addon2];
const bulkSubBundle2: BulkSubscriptionsBundle = {baseEntitlementAndAddOns: subscriptions2};

const bulkSubscriptionBundles = [bulkSubBundle1, bulkSubBundle2];

api.createSubscriptionsWithAddOns(bulkSubscriptionBundles, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$base1 = new Subscription();
$base1 -> setAccountId('13102713-9672-4e3b-8b4f-e10869fc5a59');
$base1 -> setPlanName('pistol-monthly');

$addon1 = new Subscription();
$addon1 -> setAccountId('13102713-9672-4e3b-8b4f-e10869fc5a59');
$addon1 -> setPlanName('cleaning-monthly');

$subs1 = array($base1, $addon1);

$bulkSubscriptionsBundle1 = new BulkSubscriptionsBundle();
$bulkSubscriptionsBundle1 -> setBaseEntitlementAndAddOns($subs1);

$base2 = new Subscription();
$base2 -> setAccountId('13102713-9672-4e3b-8b4f-e10869fc5a59');
$base2 -> setPlanName('shotgun-monthly');

$addon2 = new Subscription();
$addon2 -> setAccountId('13102713-9672-4e3b-8b4f-e10869fc5a59');
$addon2 -> setPlanName('laser-scope-monthly');

$subs2 = array($base2, $addon2);

$bulkSubscriptionsBundle2 = new BulkSubscriptionsBundle();
$bulkSubscriptionsBundle2 -> setBaseEntitlementAndAddOns($subs2);

$body = array($bulkSubscriptionsBundle1, $bulkSubscriptionsBundle2);

$entitlementDate = null;
$billingDate = null;
$renameKeyIfExistsAndUnused = true;
$migrated = false;
$skipResponse = false;
$callCompletion = false;
$callTimeoutSec = 3;
$pluginProperty = array("pluginProperty_example");

$result = $apiInstance->createSubscriptionsWithAddOns($body, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment, $entitlementDate, $billingDate, $renameKeyIfExistsAndUnused, $migrated, $skipResponse, $callCompletion, $callTimeoutSec, $pluginProperty);

Request Body

One or more subscription resource object corresponding to the base subscriptions need to be specified. Additional, each base subscription resource object can include zero or more subscription resource objects corresponding to add-on subscriptions. Alternatively, only a list of add-on subscription resource objects may be specified along with the base subscription bundle id. Each subscription resource object needs to include accountId and either the planName or a combination of productName, productCategory,billingPeriod and priceList.

In addition, each subscription resource can also include the following optional fields:

Query Parameters

Name Type Required Default Description
entitlementDate string no immediately Date at which the entitlement (sevice) starts in yyyy-mm-dd format. If specified, applies both to base and add-on products.
billingDate string no immediately Date at which the billing starts in yyyy-mm-dd format. If specified, applies both to base and add-on products.
renameKeyIfExistsAndUnused boolean no true If true, rename external key if it exists and is unused
migrated boolean no false If true, subscription is migrated
skipResponse boolean no false TODO
callCompletion boolean no false see below
callTimeoutSec long no unlimited? Timeout in seconds (see below)
pluginProperty array of strings false omit list of plugin properties, if any

Creating a subscription often triggers the creation of an invoice, and associated with this there is often a payment (against the invoice). If callCompletion is true, the call to this API will be delayed until the invoice is created and/or the payment is processed. However, the maximum delay in seconds will be given by callTimeoutSec.

Response

If successful, returns a status code of 201 and an empty body. In addition, a Location header is returned which contains URL to fetch the newly created bundles.

Retrieve a subscription by id

This API retrieves a subscription resource object based on its subscription id

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}

Example Request:

curl \
    -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/subscriptions/d4a919f4-7459-494f-85e5-af8880f63e90' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("905a0636-ab63-40c0-acd4-b461b6808b5d");

Subscription subscription = subscriptionApi.getSubscription(subscriptionId, 
                                                           AuditLevel.NONE, 
                                                           requestOptions);
subscription_id = "161692a4-c293-410c-a92f-939c5e3dcba7"

subscription = KillBillClient::Model::Subscription.find_by_id(subscription_id, options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '4aab9b96-c2e7-4641-a6d9-db984969201e'

subscription = subscriptionApi.get_subscription(subscription_id)
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId= 'a07be253-f7ce-4719-9959-037e05ff0777';
const audit = 'NONE';

const response: AxiosResponse<killbill.Subscription, any> = await api.getSubscription(subscriptionId, audit);
$apiInstance = $client->getSubscriptionApi();

$subscriptionId = "88d1878e-fb60-4497-95c2-ec71b4aa2a21";
$audit = "NONE";

$result = $apiInstance -> getSubscription($subscriptionId, $audit);

Example Response:

{
    "accountId":"581d86fc-7cfc-46f2-b6d4-4dbc1d98beb3",
    "bundleId":"3b7a754c-4fe3-49a4-a56c-c8f56fc4116c",
    "subscriptionId":"d4a919f4-7459-494f-85e5-af8880f63e90",
    "externalKey":"somethingSpecial",
    "bundleExternalKey":"somethingAlsoSpecial",
    "startDate":"2018-07-19",
    "productName":"Super",
    "productCategory":"BASE",
    "billingPeriod":"MONTHLY",
    "phaseType":"TRIAL",
    "priceList":"DEFAULT",
    "planName":"super-monthly",
    "state":"ACTIVE",
    "sourceType":"NATIVE",
    "cancelledDate":null,
    "chargedThroughDate":"2018-07-19",
    "billingStartDate":"2018-07-19",
    "billingEndDate":null,
    "billCycleDayLocal":18,
    "events":
    [
        {
            "eventId":"d1fc7c9a-bdcd-447c-90f4-72c8de37d457",
            "billingPeriod":"MONTHLY",
            "effectiveDate":"2018-07-19",
            "plan":"super-monthly",
            "product":"Super",
            "priceList":"DEFAULT",
            "eventType":"START_ENTITLEMENT",
            "isBlockedBilling":false,
            "isBlockedEntitlement":false,
            "serviceName":"entitlement-service",
            "serviceStateName":"ENT_STARTED",
            "phase":"super-monthly-trial",
            "auditLogs":[]
        },
        {
            "eventId":"e1cea834-9c21-450a-8ff5-8e1ebef705d1",
            "billingPeriod":"MONTHLY",
            "effectiveDate":"2018-07-19",
            "plan":"super-monthly",
            "product":"Super",
            "priceList":"DEFAULT",
            "eventType":"START_BILLING",
            "isBlockedBilling":false,
            "isBlockedEntitlement":false,
            "serviceName":"billing-service",
            "serviceStateName":"START_BILLING",
            "phase":"super-monthly-trial",
            "auditLogs":[]
        },
        {
            "eventId":"c9045227-4638-46ca-9a4a-2d3086168505",
            "billingPeriod":"MONTHLY",
            "effectiveDate":"2018-08-18",
            "plan":"super-monthly",
            "product":"Super",
            "priceList":"DEFAULT",
            "eventType":"PHASE",
            "isBlockedBilling":false,
            "isBlockedEntitlement":false,
            "serviceName":"entitlement+billing-service",
            "serviceStateName":"PHASE",
            "phase":"super-monthly-evergreen",
            "auditLogs":[]
        }
    ],
    "priceOverrides":null,
    "prices":
    [
        {
            "planName":"super-monthly",
            "phaseName":"super-monthly-trial",
            "phaseType":"TRIAL",
            "fixedPrice":0,
            "recurringPrice":null,
            "usagePrices":[]
        },
        {
            "planName":"super-monthly",
            "phaseName":"super-monthly-evergreen",
            "phaseType":"EVERGREEN",
            "fixedPrice":null,
            "recurringPrice":1000.00,
            "usagePrices":[]
        }
    ],
    "auditLogs":[]}

Query Parameters

Name Type Required Default Description
audit string no "NONE" "NONE", "MINIMAL" (only inserts), or "FULL"

Response

If successful, returns a status code of 200 and a subscription resource object.

Retrieve a subscription by key

This API retrieves a subscription resource object based on its external key

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/subscriptions/

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: application/json" \
    'http://localhost:8080/1.0/kb/subscriptions?externalKey=somethingSpecial'
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

String externalKey = "somethingSpecial";
Subscription subscription = subscriptionApi.getSubscriptionByKey(externalKey, requestOptions);
external_key = "somethingSpecial"
subscription = KillBillClient::Model::Subscription.find_by_external_key(external_key, options)
subscriptionApi = killbill.api.SubscriptionApi()

external_key = 'somethingSpecial'

subscription = subscriptionApi.get_subscription_by_key(external_key)
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const key= 'somethingSpecial';
const audit = 'NONE';

const response: AxiosResponse<killbill.Subscription, any> = await api.getSubscriptionByKey(key, audit);
$apiInstance = $client->getSubscriptionApi();

$externalKey = "somethingSpecial";
$audit = "NONE";

$result = $apiInstance -> getSubscriptionByKey($externalKey, $audit);

Example Response:

{
  "accountId": "1f979085-1765-471b-878a-5f640db4d831",
  "bundleId": "8815e8c0-afab-41b9-b793-cb8fef2382e4",
  "bundleExternalKey": "8815e8c0-afab-41b9-b793-cb8fef2382e4",
  "subscriptionId": "8e5c5339-1cad-46c6-ab18-3d5ddc1b2414",
  "externalKey": "somethingSpecial",
  "startDate": "2020-01-08",
  "productName": "Pistol",
  "productCategory": "BASE",
  "billingPeriod": "MONTHLY",
  "phaseType": "EVERGREEN",
  "priceList": "notrial",
  "planName": "pistol-monthly-notrial",
  "state": "ACTIVE",
  "sourceType": "NATIVE",
  "cancelledDate": null,
  "chargedThroughDate": "2020-05-08",
  "billingStartDate": "2020-01-08",
  "billingEndDate": null,
  "billCycleDayLocal": 8,
  "events": [
    {
      "eventId": "1d24928e-790d-4dc9-8a88-c4eaa56de392",
      "billingPeriod": "MONTHLY",
      "effectiveDate": "2020-01-08",
      "plan": "pistol-monthly-notrial",
      "product": "Pistol",
      "priceList": "notrial",
      "eventType": "START_ENTITLEMENT",
      "isBlockedBilling": false,
      "isBlockedEntitlement": false,
      "serviceName": "entitlement-service",
      "serviceStateName": "ENT_STARTED",
      "phase": "pistol-monthly-notrial-evergreen",
      "auditLogs": []
    },
    {
      "eventId": "3aaa3239-2bc6-4f04-977b-fce5de098af8",
      "billingPeriod": "MONTHLY",
      "effectiveDate": "2020-01-08",
      "plan": "pistol-monthly-notrial",
      "product": "Pistol",
      "priceList": "notrial",
      "eventType": "START_BILLING",
      "isBlockedBilling": false,
      "isBlockedEntitlement": false,
      "serviceName": "billing-service",
      "serviceStateName": "START_BILLING",
      "phase": "pistol-monthly-notrial-evergreen",
      "auditLogs": []
    }
  ],
  "priceOverrides": null,
  "prices": [
    {
      "planName": "pistol-monthly-notrial",
      "phaseName": "pistol-monthly-notrial-evergreen",
      "phaseType": "EVERGREEN",
      "fixedPrice": null,
      "recurringPrice": 19.95,
      "usagePrices": []
    }
  ],
  "auditLogs": []
}

Query Parameters

Name Type Required Default Description
externalKey String yes none The subscription external key
audit string no "NONE" "NONE", "MINIMAL" (only inserts), or "FULL"

Response

If successful, returns a status code of 200 and a subscription resource object.

Update the BCD associated with a subscription

This API allows you to change the Bill Cycle Date, BCD, for a given subscription. This only applies to subscriptions whose recurring term is month based -- e.g MONTHLY, ANNUAL, ...

For example if a given subscription was invoiced on the 1st, then one could use this API to realign invoicing, let's say on the 16th.

HTTP Request

PUT http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/bcd

Example Request:

curl -v \
    -X PUT \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '{ "billCycleDayLocal": 16 }' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/bcd' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("905a0636-ab63-40c0-acd4-b461b6808b5d");

Subscription updatedSubscription = new Subscription();
updatedSubscription.setSubscriptionId(subscriptionId);
updatedSubscription.setBillCycleDayLocal(9);

LocalDate effectiveFromDate = null;

subscriptionApi.updateSubscriptionBCD(subscriptionId, 
                                      updatedSubscription, 
                                      effectiveFromDate, 
                                      requestOptions);
user = "demo"
reason = nil
comment = nil

subscription                      = KillBillClient::Model::Subscription.new
subscription.subscription_id      = "161692a4-c293-410c-a92f-939c5e3dcba7"
subscription.bill_cycle_day_local = 16

effective_from_date  = nil
force_past_effective_date = nil

subscription.update_bcd(user, 
                        reason, 
                        comment, 
                        effective_from_date, 
                        force_past_effective_date, 
                        options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '161692a4-c293-410c-a92f-939c5e3dcba7'
body = Subscription(subscription_id=subscription_id,
                    bill_cycle_day_local=26)

subscriptionApi.update_subscription_bcd(subscription_id, 
                                        body, 
                                        created_by='demo',
                                        reason='reason', 
                                        comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscription: Subscription = {billCycleDayLocal: 10};
const subscriptionId = 'e5254822-680f-4720-b5e1-a7146cefb904';

api.updateSubscriptionBCD(subscription, subscriptionId, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$body = new Subscription();
$body -> setBillCycleDayLocal(5);
$subscriptionId = "52bee217-4ed9-40a3-8b89-baa1cb1e6f95";

$effectiveFromDate = null;
$forceNewBcdWithPastEffectiveDate = false;

$apiInstance->updateSubscriptionBCD($body, $xKillbillCreatedBy, $subscriptionId, $xKillbillReason, $xKillbillComment,  $effectiveFromDate, $forceNewBcdWithPastEffectiveDate);

Request Body

The new BCD needs to be specified in the request body via the billCycleDayLocal field.

Query Parameters

Name Type Required Default Description
effectiveFromDate string no immediate Date on which this change becomes effective in yyyy-mm-dd format.
forceNewBcdWithPastEffectiveDate boolean no false See below

By default the effective date must be in the future so as to not modify existing invoices. Setting forceNewBcdWithPastEffectiveDate to true allows the date to be set in the past.

Secondly, even after this endpoint is executed, the Retrieve a Subscription endpoint will still return the old BCD until an invoice is generated on the new BCD.

Response

If successful, returns a status code of 204 and an empty body.

Update the subscription quantity

This API allows you to change the subscription quantity.

HTTP Request

PUT http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/quantity

Example Request:

curl -v \
    -X PUT \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '{ 
            "quantity": "2" 
        }' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/c20715fa-8d69-488d-a094-51da0cdf999b/quantity'
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("f0143401-5b9b-41d1-b9c0-8513f1f0cf0b");

Subscription body = new Subscription();
body.setQuantity(3);
LocalDate effectiveFromDate = null;

subscriptionApi.updateSubscriptionQuantity(subscriptionId, body, effectiveFromDate, requestOptions);
TODO
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '7b3f0181-d9e8-4886-a90a-af35e671f5f0'
body = Subscription(subscription_id=subscription_id,
                    quantity=3)

subscriptionApi.update_subscription_quantity(subscription_id,
                                             body,
                                             created_by='demo',
                                             reason='reason',
                                             comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscription: Subscription = {quantity: 3};
    const subscriptionId = 'e5254822-680f-4720-b5e1-a7146cefb904';

api.updateSubscriptionQuantity(subscription, subscriptionId, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$body = new Subscription();
$body -> setQuantity(3);
$subscriptionId = "88d1878e-fb60-4497-95c2-ec71b4aa2a21";

$effectiveFromDate = null;
$forceNewBcdWithPastEffectiveDate = false;

$apiInstance -> updateSubscriptionQuantity($body, $xKillbillCreatedBy, $subscriptionId, $xKillbillReason, $xKillbillComment, $effectiveFromDate, $forceNewBcdWithPastEffectiveDate);

Request Body

The quantity needs to be specified in the request body via the quantity field.

Query Parameters

Name Type Required Default Description
effectiveFromDate string no immediate Date on which this change becomes effective in yyyy-mm-dd format.
forceNewQuantityWithPastEffectiveDate boolean no false See below

By default the effective date must be in the future so as to not modify existing invoices. Setting forceNewQuantityWithPastEffectiveDate to true allows the date to be set in the past.

Response

If successful, returns a status code of 204 and an empty body.

Change subscription plan

This API allows you to upgrade or downgrade a given subscription to a new Plan.

HTTP Request

PUT http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}

Example Request:

# With productName, billingPeriod, priceList
curl -v \
    -X PUT \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '{ 
            "productName": "Sports", 
            "billingPeriod": "MONTHLY", 
            "priceList": "DEFAULT"
        }' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712'

# with planName
curl -v \
    -X PUT \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '{ 
            "planName": "sports-monthly"
        }' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/e1868fa6-ea97-493e-870d-50787f4b5921'
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("905a0636-ab63-40c0-acd4-b461b6808b5d");

Subscription newInput = new Subscription();
newInput.setSubscriptionId(subscriptionId);

newInput.setPlanName("shotgun-monthly");

LocalDate requestedDate = null;
Map<String, String> NULL_PLUGIN_PROPERTIES = null;

//specify either requestedDate or BillingActionPolicy
subscriptionApi.changeSubscriptionPlan(subscriptionId, 
                                       newInput, 
                                       requestedDate, 
                                       BillingActionPolicy.IMMEDIATE, 
                                       NULL_PLUGIN_PROPERTIES, 
                                       requestOptions);
user = "demo"
reason = nil
comment = nil

input = {
           :productName => 'Super', 
           :billingPeriod => 'MONTHLY', 
           :priceList => 'DEFAULT'
         }

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "21541d56-c34a-4012-990a-2250e2822019"         

requested_date = nil
billing_policy = nil
call_completion = false
target_phase_type = nil

subscription.change_plan(input, 
                         user, 
                         reason, 
                         comment, 
                         requested_date, 
                         billing_policy,
                         target_phase_type, 
                         call_completion, 
                         options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '97278000-72fd-45d7-9b67-e44690bdb074'
body = Subscription(plan_name='pistol-monthly')

subscriptionApi.change_subscription_plan(subscription_id,
                                         body,
                                         created_by='demo',
                                         reason='reason',
                                         comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscription: Subscription = {planName: "pistol-monthly-notrial"};
const subscriptionId = 'e5254822-680f-4720-b5e1-a7146cefb904';

api.changeSubscriptionPlan(subscription, subscriptionId, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$body = new Subscription();
$body -> setPlanName('pistol-monthly-notrial');

$requestedDate = null;
$callCompletion = false;
$callTimeoutSec = 3;
$billingPolicy = null;
$pluginProperty = array("pluginProperty_example");

$subscriptionId = "52bee217-4ed9-40a3-8b89-baa1cb1e6f95";

$apiInstance->changeSubscriptionPlan($body, $xKillbillCreatedBy, $subscriptionId, $xKillbillReason, $xKillbillComment, $requestedDate, $callCompletion, $callTimeoutSec, $billingPolicy, $pluginProperty);

Request Body

A subscription resource object specifying either the planName or a combination of productName, billingPeriod and priceList.

Query Parameters

Name Type Required Default Description
billingPolicy string no default Billing policy that will be used to make this change effective (see below)
requestedDate string no immediate Date/DateTime at which this change should become effective in yyyy-mm-dd/yyyy-mm-ddThh:mm format.
callCompletion boolean no false see below
callTimeoutSec long no unlimited? Timeout in seconds (see below)
pluginProperty array of strings false omit list of plugin properties, if any

billingPolicy: Possible values are START_OF_TERM, END_OF_TERM, IMMEDIATE, or ILLEGAL

requestedDate: This date is only used if no billingPolicy was specified.

Changing the plan associated to a subscription often triggers the creation of an invoice, and associated with this there is often a payment (against the invoice). If callCompletion is true, the call to this API will be delayed until the invoice is created and/or the payment is processed. However, the maximum delay in seconds will be given by callTimeoutSec.

Response

If successful, returns a status code of 204 and an empty body.

Undo a pending change plan on a subscription

This endpoint allows a pending Plan change (plan change request with a future effective date) for a given subscription to be canceled. Note that if the plan change is already effective, then it cannot be undone.

HTTP Request

PUT http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/undoChangePlan

Example Request:

curl \
    -X PUT \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/undoChangePlan' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("1bb4b638-3886-4f73-90a5-89eb6d1bcf7f");
Map<String, String> NULL_PLUGIN_PROPERTIES = null;

subscriptionApi.undoChangeSubscriptionPlan(subscriptionId, 
                                           NULL_PLUGIN_PROPERTIES, 
                                           requestOptions);
user = "demo"
reason = nil
comment = nil

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "fbe97f23-30da-4f7e-9987-3280034c5258"

subscription.undo_change_plan(user, 
                              reason, 
                              comment, 
                              options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = 'f5bb14ed-c6e8-4895-8d4e-34422e12cdfa'

subscriptionApi.undo_change_subscription_plan(subscription_id,
                                              created_by='demo',
                                              reason='reason',
                                              comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId= '1664777f-f194-48fd-a274-e883063790b1';

api.undoChangeSubscriptionPlan(subscriptionId, 'created-by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$subscriptionId = "88d1878e-fb60-4497-95c2-ec71b4aa2a21";
$pluginProperty = array("pluginProperty_example");

$apiInstance->undoChangeSubscriptionPlan($subscriptionId, $xKillbillCreatedBy, $pluginProperty, $xKillbillReason, $xKillbillComment);

Query Parameters

Query Parameters

Name Type Required Default Description
pluginProperty array of strings false omit list of plugin properties, if any

Response

If successful, returns a status code of 204 and an empty body.

Cancel a subscription

This API cancels an existing subscription.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}

Example Request:

curl  -v \
    -X DELETE \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712'
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("905a0636-ab63-40c0-acd4-b461b6808b5d");
LocalDate requestedDate = null;
EntitlementActionPolicy entitlementPolicy = null;
BillingActionPolicy billingPolicy = null;
Map<String, String> NULL_PLUGIN_PROPERTIES = null;

subscriptionApi.cancelSubscriptionPlan(subscriptionId,
                                       requestedDate, 
                                       entitlementPolicy, 
                                       billingPolicy, 
                                       NULL_PLUGIN_PROPERTIES, 
                                       requestOptions);
user = "demo"
reason = nil
comment = nil

requested_date = nil
entitlement_policy = nil
billing_policy = nil
use_requested_date_for_billing = nil

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "21541d56-c34a-4012-990a-2250e2822019"

subscription.cancel(user, 
                    reason, 
                    comment, 
                    requested_date, 
                    entitlement_policy, 
                    billing_policy, 
                    use_requested_date_for_billing, 
                    options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = 'ee508b5b-46b8-42a7-8988-16c0470de4ae'

subscriptionApi.cancel_subscription_plan(subscription_id,
                                         created_by='demo',
                                         reason='reason',
                                         comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId= '66d3d89f-e074-49cc-bf9a-96a2e57d15ab';

api.cancelSubscriptionPlan(subscriptionId, 'created-by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$subscriptionId = "71ccbec4-af0e-4011-8f65-9acb89204e45";
$requestedDate = null;
$callCompletion = false;
$callTimeoutSec = 5;
$entitlementPolicy = null;
$billingPolicy = null;
$useRequestedDateForBilling = false;
$pluginProperty = array("pluginProperty_example");

$apiInstance -> cancelSubscriptionPlan($subscriptionId, $xKillbillCreatedBy, $requestedDate, $callCompletion, $callTimeoutSec, $entitlementPolicy, $billingPolicy, $useRequestedDateForBilling, $pluginProperty, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
requestedDate string no immediate Date/DateTime at which this change should become effective in yyyy-mm-dd/yyyy-mm-ddThh:mm format.
entitlementPolicy string no IMMEDIATE entitlement policy (see below)
billingPolicy string no default policy from catalog if present, otherwise END_OF_TERM billing policy (see below)
useRequestedDateForBilling boolean no false use requestedDate for billing
callCompletion boolean no false see below
callTimeoutSec long no unlimited? Timeout in seconds (see below)
pluginProperty array of strings false omit list of plugin properties, if any

entitlementPolicy: Possible values are IMMEDIATE, END_OF_TERM

billingPolicy: Possible values are START_OF_TERM, END_OF_TERM, or IMMEDIATE

Creating a subscription often triggers the creation of an invoice, and associated with this there is often a payment (against the invoice). If callCompletion is true, the call to this API will be delayed until the invoice is created and/or the payment is processed. However, the maximum delay in seconds will be given by callTimeoutSec.

Since we offer the ability to control the cancelation date for both entitlement (service) and billing either through policies, dates or null values (now), it is important to understand how those parameters work:

So, the common use case would require the following:

The reason for all this complexity is to allow to control entitlement and billing date separately, and also avoid users to have to compute dates to achieve certain behavior by relying on well defined policies.

Other Notes: * If a subscription is created with a future date and if the cancel method is invoked for immediate cancellation, the cancellation takes effect only after the subscription creation date is reached. Thus, the subscription remains in PENDING state until the subscription creation date is reached after which it is moved to the CANCELLED state.

Returns

If successful, returns a status code of 204 and an empty body.

Un-cancel a subscription

This endpoint allows you to undo a pending cancellation (cancellation request with a future effective date) for a given subscription.

HTTP Request

PUT http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/uncancel

Example Request:

curl \
    -X PUT \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/uncancel' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("1bb4b638-3886-4f73-90a5-89eb6d1bcf7f");
Map<String, String> NULL_PLUGIN_PROPERTIES = null;

subscriptionApi.uncancelSubscriptionPlan(subscriptionId, 
                                         NULL_PLUGIN_PROPERTIES, 
                                         requestOptions);
user = "demo"
reason = nil
comment = nil

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "fbe97f23-30da-4f7e-9987-3280034c5258"

subscription.uncancel(user, 
                      reason, 
                      comment, 
                      options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = 'f5bb14ed-c6e8-4895-8d4e-34422e12cdfa'

subscriptionApi.uncancel_subscription_plan(subscription_id,
                                           created_by='demo',
                                           reason='reason',
                                           comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId= '1664777f-f194-48fd-a274-e883063790b1';

api.uncancelSubscriptionPlan(subscriptionId, 'created-by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$subscriptionId = "5499095e-36c3-4eff-9feb-7bbbabdde9df";
$pluginProperty = array("pluginProperty_example");

$apiInstance -> uncancelSubscriptionPlan($subscriptionId, $xKillbillCreatedBy, $pluginProperty, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
pluginProperty array of strings false omit list of plugin properties, if any

Returns

If successful, returns a status code of 204 and an empty body.

Blocking State

See section Account Blocking State for an introduction to blocking states.

Block a subscription

Provides a low level interface to add a BlockingState event for this subscription.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/block

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 "X-Killbill-CreatedBy: demo" \
    -d '{ 
            "stateName": "STATE",
            "service": "ServiceStateService",
            "isBlockChange": false,
            "isBlockEntitlement": false,
            "isBlockBilling": false
    }' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/block' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("161692a4-c293-410c-a92f-939c5e3dcba7");

BlockingState blockingState = new BlockingState();
blockingState.setStateName("STATE1");
blockingState.setService("ServiceStateService");
blockingState.setIsBlockChange(false);
blockingState.setIsBlockBilling(false);
blockingState.setIsBlockEntitlement(false);

LocalDate requestedDate = new LocalDate("2013-08-01");
Map<String, String> pluginProperty = Collections.emptyMap();

BlockingStates result = subscriptionApi.addSubscriptionBlockingState(subscriptionId,
                                                                     blockingState,
                                                                     requestedDate,
                                                                     pluginProperty,
                                                                     requestOptions);
user = "demo"
reason = nil
comment = nil

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "161692a4-c293-410c-a92f-939c5e3dcba7"

state_name = 'STATE1'
service = 'ServiceStateService'
block_change = false
block_entitlement = false
block_billing = false
requested_date = nil

subscription.set_blocking_state(state_name, 
                                service, 
                                block_change, 
                                block_entitlement, 
                                block_billing, 
                                requested_date, 
                                user, 
                                reason,
                                comment, 
                                options)
subscriptionApi = killbill.api.SubscriptionApi()

body = BlockingState(state_name='STATE1',
                     service='ServiceStateService',
                     is_block_change=False,
                     is_block_entitlement=False,
                     is_block_billing=False)
subscription_id = '33aa2952-cea2-4cad-900a-9731c1042e54'

subscriptionApi.add_subscription_blocking_state(subscription_id,
                                                body,
                                                created_by='demo',
                                                reason='reason',
                                                comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const blockingState: BlockingState = {stateName: "STATE1", service: "ServiceStateService", isBlockChange: true, isBlockEntitlement: false, isBlockBilling: false};
const subscriptionId = 'b6000207-42fd-40ea-9c8e-297d9adc1574';

api.addSubscriptionBlockingState(blockingState, subscriptionId, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$blockingState = new BlockingState();
$blockingState -> setStateName('STATE1');
$blockingState -> setService('ServiceStateService1');
$blockingState -> setIsBlockChange(true);
$blockingState -> setIsBlockBilling(true);
$blockingState -> setIsBlockEntitlement(true);

$subscriptionId = "3f4a2efd-a8c1-4f85-9266-32bd6f7113ba";
$requestedDate = new DateTime("2023-10-20");
$pluginProperty = array("pluginProperty_example");

$result = $apiInstance->addSubscriptionBlockingState($blockingState, $xKillbillCreatedBy, $subscriptionId, $xKillbillReason, $xKillbillComment, $requestedDate, $pluginProperty);

Request Body

A blocking state resource representing the intended new blocking state.

{
  "blockedId": "943c4fd0-9000-4975-a3a8-09712223e1f8",
  "stateName": "STATE1",
  "service": "ServiceStateService",
  "isBlockChange": false,
  "isBlockEntitlement": false,
  "isBlockBilling": true,
  "effectiveDate": "2020-07-18T18:22:30.376Z",
  "type": "SUBSCRIPTION"
}

Query Parameters

Name Type Required Default Description
requestedDate string no immediate Date/DateTime to begin blocking in yyyy-mm-dd/yyyy-mm-ddThh:mm format.

Response

If successful, returns a status code of 201 and an empty body. In addition, a Location header is returned which contains the URL to retrieve the subscription blocking states for the account.

Custom Fields

Custom fields are {key, value} attributes that can be attached to any customer resources. For more on custom fields see Custom Fields. These endpoints manage custom fields associated with Subscription objects.

Add custom fields to subscription

Adds one or more custom fields to a subscription object. Existing custom fields are not disturbed.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/customFields

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 "X-Killbill-CreatedBy: demo" \
    -d '[{ 
            "name": "Test Custom Field",
            "value": "test_value"
    }]' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/customFields' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("cca08349-8b26-41c7-bfcc-2e3cf70a0f28");

final List<AuditLog> EMPTY_AUDIT_LOGS = Collections.emptyList();

CustomFields customFields = new CustomFields();
customFields.add(new CustomField(null, 
                                 subscriptionId, 
                                 ObjectType.SUBSCRIPTION, 
                                 "Test Custom Field", 
                                 "test_value", 
                                 EMPTY_AUDIT_LOGS));

subscriptionApi.createSubscriptionCustomFields(subscriptionId, 
                                               customFields, 
                                               requestOptions);
user = "demo"
reason = nil
comment = nil

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "2207150d-0652-43eb-abbe-2cbd0092b744"

custom_field = KillBillClient::Model::CustomFieldAttributes.new
custom_field.name = 'Test Custom Field'
custom_field.value = 'test_value'

subscription.add_custom_field(custom_field,
                              user,
                              reason,
                              comment,
                              options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '33aa2952-cea2-4cad-900a-9731c1042e54'
body = CustomField(name='Test Custom Field', value='test_value')

subscriptionApi.create_subscription_custom_fields(subscription_id,
                                                  [body],
                                                  created_by='demo',
                                                  reason='reason',
                                                  comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId = 'b6000207-42fd-40ea-9c8e-297d9adc1574';

const customField: CustomField = {name: "Test Custom Field", value: "test_value"};
const customFields = [customField];

api.createSubscriptionCustomFields(customFields, subscriptionId, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$subscriptionId = "3f4a2efd-a8c1-4f85-9266-32bd6f7113ba";

$customField = new CustomField();
$customField -> setName('Test Custom Field');
$customField -> setValue('test_value');
$body = array($customField);

$apiInstance->createSubscriptionCustomFields($body, $xKillbillCreatedBy, $subscriptionId, $xKillbillReason, $xKillbillComment);

Request Body

A list of objects giving the name and value of the custom field, or fields, to be added. For example:

[ { "name": "CF1", "value": "123" } ]

Query Parameters

None.

Response

If successful, returns a 201 status code.In addition, a Location header is returned giving the URL to retrieve the custom fields associated with the subscription.

Retrieve subscription custom fields

Returns any custom field objects associated with the specified subscription

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/customFields

Example Request:

curl \
    -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/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/customFields' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("cca08349-8b26-41c7-bfcc-2e3cf70a0f28");

List<CustomField> customFields = subscriptionApi.getSubscriptionCustomFields(subscriptionId,
                                                                             AuditLevel.NONE,
                                                                             requestOptions);
subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "2207150d-0652-43eb-abbe-2cbd0092b744"

audit = 'NONE'
fields = subscription.custom_fields(audit, options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '33aa2952-cea2-4cad-900a-9731c1042e54'

fields = subscriptionApi.get_subscription_custom_fields(subscription_id)
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId = 'e5254822-680f-4720-b5e1-a7146cefb904';
const audit = 'NONE';

const response: AxiosResponse<killbill.CustomField[], any> = await api.getSubscriptionCustomFields(subscriptionId, audit, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$subscriptionId = "3f4a2efd-a8c1-4f85-9266-32bd6f7113ba";
$audit = "NONE";

$result = $apiInstance->getSubscriptionCustomFields($subscriptionId, $audit);

Example Response:

[
    {
        "customFieldId":"439ed0f8-9b37-4688-bace-e2595b1d3801",
        "objectId":"77e23878-8b9d-403b-bf31-93003e125712",
        "objectType":"SUBSCRIPTION",
        "name":"Test Custom Field",
        "value":"test_value",
        "auditLogs":[]
    }
]

Query Parameters

Name Type Required Default Description
audit string no "NONE" Level of audit information to return:"NONE", "MINIMAL" (only inserts), or "FULL"

Response

If successful, returns a status code of 200 and a (possibly empty) list of custom field objects.

Modify custom fields for a subscription

Modifies the value of one or more existing custom fields associated with a subscription. Note that it is not possible to modify the name of a custom field, it is only possible to modify its value.

HTTP Request

PUT http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/customFields

Example Request:

curl -v \
    -X PUT \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -d '[{ 
            "customFieldId": "439ed0f8-9b37-4688-bace-e2595b1d3801",
            "value": "NewValue"
    }]' \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/customFields' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("cca08349-8b26-41c7-bfcc-2e3cf70a0f28");
UUID customFieldId = UUID.fromString("9913e0f6-b5ef-498b-ac47-60e1626eba8f");

CustomField customFieldModified = new CustomField();
customFieldModified.setCustomFieldId(customFieldId);
customFieldModified.setValue("NewValue");
CustomFields customFields = new CustomFields();
customFields.add(customFieldModified);

subscriptionApi.modifySubscriptionCustomFields(subscriptionId, 
                                               customFields, 
                                               requestOptions);
user = "demo"
reason = nil
comment = nil

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "2207150d-0652-43eb-abbe-2cbd0092b744"

custom_field = KillBillClient::Model::CustomFieldAttributes.new
custom_field.custom_field_id = 'a04adaca-78a4-41fe-b512-a8d620aad456'
custom_field.value = 'test_modify_value'

subscription.modify_custom_field(custom_field,
                                 user,
                                 reason,
                                 comment,
                                 options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '33aa2952-cea2-4cad-900a-9731c1042e54'
custom_field_id = '3a26be42-a153-4894-ac3d-93ad2e38e05b'
body = CustomField(custom_field_id=custom_field_id,
                   value='modified_value')

subscriptionApi.modify_subscription_custom_fields(subscription_id,
                                                  [body],
                                                  created_by='demo',
                                                  reason='reason',
                                                  comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId = 'b6000207-42fd-40ea-9c8e-297d9adc1574';

const customField: CustomField = {customFieldId: "d8f2e80d-9fd8-48e7-b564-a541a0a7621d", value: "new_value"};
const customFields = [customField];

api.modifySubscriptionCustomFields(customFields, subscriptionId, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$subscriptionId = "3f4a2efd-a8c1-4f85-9266-32bd6f7113ba";

$customField = new CustomField();
$customField -> setCustomFieldId('73e399fe-efaa-4f05-a5fe-08f10608c345');
$customField -> setValue('new_value');
$body = array($customField);

$apiInstance->modifySubscriptionCustomFields($body, $xKillbillCreatedBy, $subscriptionId, $xKillbillReason, $xKillbillComment);

Request Body

A list of objects specifying the id and the new value for the custom fields to be modified. For example:

[ { "customFieldId": "6d4c073b-fd89-4e39-9802-eba65f42492f", "value": "123" } ]

Although the fieldName and objectType can be specified in the request body, these cannot be modified, only the field value can be modified.

Query Parameters

None.

Response

If successful, returns a status code of 204 and an empty body.

Remove custom fields from subscription

Delete one or more custom fields from a subscription. It accepts query parameters corresponding to the custom field ids to be deleted. If no query parameters are specified, it deletes all the custom fields corresponding to the subscription.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/customFields

Example Request:

curl -v \
    -X DELETE \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/customFields?customField=439ed0f8-9b37-4688-bace-e2595b1d3801' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("cca08349-8b26-41c7-bfcc-2e3cf70a0f28");
UUID customFieldsId = UUID.fromString("9913e0f6-b5ef-498b-ac47-60e1626eba8f");
List<UUID> customFieldsList = List.of(customFieldsId);

subscriptionApi.deleteSubscriptionCustomFields(subscriptionId, 
                                               customFieldsList, 
                                               requestOptions);
user = "demo"
reason = nil
comment = nil

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "2207150d-0652-43eb-abbe-2cbd0092b744"

custom_field_id = 'a04adaca-78a4-41fe-b512-a8d620aad456'

subscription.remove_custom_field(custom_field_id,
                                 user,
                                 reason,
                                 comment,
                                 options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = 'e5254822-680f-4720-b5e1-a7146cefb904'
custom_fields = ['194bcfc8-340f-4592-acd2-ffc1fc461e96']

subscriptionApi.delete_subscription_custom_fields(subscription_id=subscription_id,
                                                  custom_field=custom_fields,
                                                  created_by='demo',
                                                  reason='reason',
                                                  comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId = 'b6000207-42fd-40ea-9c8e-297d9adc1574';

const customField = 'd8f2e80d-9fd8-48e7-b564-a541a0a7621d';
const customFields = [customField];

api.deleteSubscriptionCustomFields(subscriptionId, 'created_by', customFields);
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$subscriptionId = "3f4a2efd-a8c1-4f85-9266-32bd6f7113ba";
$customFields = array("73e399fe-efaa-4f05-a5fe-08f10608c345");

$apiInstance->deleteSubscriptionCustomFields($subscriptionId, $xKillbillCreatedBy, $customFields, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
customField string no none Custom field ID that should be deleted. Multiple custom fields can be deleted by specifying a separate customField parameter corresponding to each field

Response

If successful, returns a status code of 204 and an empty body.

Tags

See section Tags for an introduction.

Note: None of the system tags are applicable for subscriptions, only a user tag can be associated with a subscription.

Add tags to subscription

This API adds one or more tags to a subscription. The tag definition corresponding to the tag to be added must already exist.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/tags

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 "X-Killbill-CreatedBy: demo" \
    -d '[
            "353752dd-9041-4450-b782-a8bb03a923c8"
        ]' \
  'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/tags' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("1bb4b638-3886-4f73-90a5-89eb6d1bcf7f");
UUID tagDefinitionId = UUID.fromString("353752dd-9041-4450-b782-a8bb03a923c8");

subscriptionApi.createSubscriptionTags(subscriptionId, 
                                                     List.of(tagDefinitionId), 
                                                     requestOptions);
user = "demo"
reason = nil
comment = nil

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "92820d1c-1d4c-46eb-9010-26b0626a1927"

tag_name = 'good_sub'

subscription.add_tag(tag_name,
                     user,
                     reason,
                     comment,
                     options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '92820d1c-1d4c-46eb-9010-26b0626a1927'
tagDefIds = ['30363fe5-310d-4446-b000-d7bb6e6662e2']

subscriptionApi.create_subscription_tags(subscription_id,
                                         tagDefIds,
                                         created_by='demo',
                                         reason='reason',
                                         comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId = '92820d1c-1d4c-46eb-9010-26b0626a1927';

const tagDefIds = ['06d991f7-f06a-4e45-80d2-c3b44a97f8bc'];

api.createSubscriptionTags(tagDefIds, subscriptionId, 'created_by');
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$subscriptionId = "92820d1c-1d4c-46eb-9010-26b0626a1927";
$tagDefIds = array("30363fe5-310d-4446-b000-d7bb6e6662e2");

$apiInstance->createSubscriptionTags($tagDefIds, $xKillbillCreatedBy, $subscriptionId, $xKillbillReason, $xKillbillComment);

Request Body

A JSON array corresponding to the tag definition IDs to be added.

Query Parameters

None.

Returns

If successful, returns a 201 status code. In addition, a Location header is returned giving the URL to retrieve the tags associated with the subscription.

Retrieve subscription tags

Retrieve all tags attached to this subscription.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/tags

Example Request:

curl \
    -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/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/tags' 
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("1bb4b638-3886-4f73-90a5-89eb6d1bcf7f");
Boolean includedDeleted = false; // Will not include deleted tags

List<Tag> tags = subscriptionApi.getSubscriptionTags(subscriptionId, 
                                                     includedDeleted, 
                                                     AuditLevel.FULL, 
                                                     requestOptions);
subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "92820d1c-1d4c-46eb-9010-26b0626a1927"

included_deleted = false
audit = 'NONE'

tags = subscription.tags(included_deleted,
                  audit,
                  options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '92820d1c-1d4c-46eb-9010-26b0626a1927'

tags = subscriptionApi.get_subscription_tags(subscription_id)
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId = '92820d1c-1d4c-46eb-9010-26b0626a1927';
const includeDeleted = false;
const audit = 'NONE';

const response: AxiosResponse<killbill.Tag[], any> = await api.getSubscriptionTags(subscriptionId, includeDeleted, audit);
$apiInstance = $client->getSubscriptionApi();

$subscriptionId = "92820d1c-1d4c-46eb-9010-26b0626a1927";
$includedDeleted = false;
$audit = "NONE";

$result = $apiInstance->getSubscriptionTags($subscriptionId, $includedDeleted, $audit);

Example Response:

[
  {
    "tagId":"d0513754-56a9-4694-abb1-3ac46c72e861",
    "objectType":"SUBSCRIPTION",
    "objectId":"77e23878-8b9d-403b-bf31-93003e125712",
    "tagDefinitionId":"353752dd-9041-4450-b782-a8bb03a923c8",
    "tagDefinitionName":"foo",
    "auditLogs":[]
  }
]

Query Parameters

Name Type Required Default Description
includedDeleted boolean no false If true, include deleted tags
audit string no "NONE" Level of audit information to return: "NONE", "MINIMAL", or "FULL"

Response

If successful, returns a status code of 200 and a list of tag objects.

Remove tags from subscription

This API deletes one or more tags attached to a subscription.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/tags

Example Request:

curl -v \
    -X DELETE \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    'http://127.0.0.1:8080/1.0/kb/subscriptions/77e23878-8b9d-403b-bf31-93003e125712/tags?tagDef=353752dd-9041-4450-b782-a8bb03a923c8'  
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("1bb4b638-3886-4f73-90a5-89eb6d1bcf7f");
UUID tagDefinitionId = UUID.fromString("353752dd-9041-4450-b782-a8bb03a923c8");

subscriptionApi.deleteSubscriptionTags(subscriptionId, List.of(tagDefinitionId), requestOptions);
user = "demo"
reason = nil
comment = nil

subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "92820d1c-1d4c-46eb-9010-26b0626a1927"

tag_name = 'good_sub'

subscription.remove_tag(tag_name,
                        user,
                        reason,
                        comment,
                        options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '92820d1c-1d4c-46eb-9010-26b0626a1927'
tagDefIds = ['30363fe5-310d-4446-b000-d7bb6e6662e2']

subscriptionApi.delete_subscription_tags(subscription_id,
                                         tag_def=tagDefIds,
                                         created_by='demo',
                                         reason='reason',
                                         comment='comment')
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId = '92820d1c-1d4c-46eb-9010-26b0626a1927';

const tagDefIds = ['06d991f7-f06a-4e45-80d2-c3b44a97f8bc'];

api.deleteSubscriptionTags(subscriptionId, 'created_by', tagDefIds);
$apiInstance = $client->getSubscriptionApi();

$xKillbillCreatedBy = "user";
$xKillbillReason = "reason";
$xKillbillComment = "comment";

$subscriptionId = "92820d1c-1d4c-46eb-9010-26b0626a1927";
$tagDefIds = array("30363fe5-310d-4446-b000-d7bb6e6662e2");

$apiInstance->deleteSubscriptionTags($subscriptionId, $xKillbillCreatedBy, $tagDefIds, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
tagDef string true none A tag definition ID identifying the tag that should be removed. Multiple tags can be deleted by specifying a separate tagDef parameter corresponding to each tag.

Response

If successful, returns a status code of 204 and an empty body.

Audit Logs

Audit logs provide a record of events that occur involving various specific resources. For details on audit logs see Audit and History.

Retrieve subscription audit logs with history by subscription id

Retrieve a list of audit log records showing changes to the subscription. History information (a copy of the full subscription object) is included with each record.

Some examples:

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/subscriptions/{subscriptionId}/auditLogsWithHistory

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: application/json" \
    "http://localhost:8080/1.0/kb/subscriptions/70b6856e-6938-495f-9ae9-0a8ec0571c37/auditLogsWithHistory"
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionId = UUID.fromString("bc9b98e8-7497-4330-aa42-1fbc71a3d19c");

List<AuditLog> auditLog = subscriptionApi.getSubscriptionAuditLogsWithHistory(subscriptionId, requestOptions);
subscription = KillBillClient::Model::Subscription.new
subscription.subscription_id = "88f0cd47-ed92-4143-89e1-31b79c533208"

audit_logs = subscription.audit_logs_with_history(options)
subscriptionApi = killbill.api.SubscriptionApi()

subscription_id = '92820d1c-1d4c-46eb-9010-26b0626a1927'

auditlogs = subscriptionApi.get_subscription_audit_logs_with_history(subscription_id)
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const subscriptionId = '92820d1c-1d4c-46eb-9010-26b0626a1927';

const response: AxiosResponse<killbill.AuditLog[], any> = await api.getSubscriptionAuditLogsWithHistory(subscriptionId);
$apiInstance = $client->getSubscriptionApi();

$subscriptionId = "92820d1c-1d4c-46eb-9010-26b0626a1927";

$result = $apiInstance->getSubscriptionAuditLogsWithHistory($subscriptionId);

Example Response:

[
  {
    "changeType": "INSERT",
    "changeDate": "2019-02-22T22:38:10.000Z",
    "objectType": "SUBSCRIPTION",
    "objectId": "70b6856e-6938-495f-9ae9-0a8ec0571c37",
    "changedBy": "admin",
    "reasonCode": null,
    "comments": null,
    "userToken": "1f03e074-dea1-45c5-aee3-c9464886f476",
    "history": {
      "id": null,
      "createdDate": "2019-02-22T22:38:10.000Z",
      "updatedDate": "2019-02-22T22:38:10.000Z",
      "recordId": 465,
      "accountRecordId": 10,
      "tenantRecordId": 1,
      "bundleId": "d1b329c7-7dcf-466c-aaca-47bff304dab0",
      "category": "BASE",
      "startDate": "2019-02-22T22:38:10.000Z",
      "bundleStartDate": "2019-02-22T22:38:10.000Z",
      "chargedThroughDate": null,
      "migrated": false,
      "tableName": "SUBSCRIPTIONS",
      "historyTableName": "SUBSCRIPTION_HISTORY"
    }
  },
  {
    "changeType": "UPDATE",
    "changeDate": "2019-02-22T22:38:10.000Z",
    "objectType": "SUBSCRIPTION",
    "objectId": "70b6856e-6938-495f-9ae9-0a8ec0571c37",
    "changedBy": "SubscriptionBaseTransition",
    "reasonCode": null,
    "comments": null,
    "userToken": "1f03e074-dea1-45c5-aee3-c9464886f476",
    "history": {
      "id": null,
      "createdDate": "2019-02-22T22:38:10.000Z",
      "updatedDate": "2019-02-22T22:38:10.000Z",
      "recordId": 465,
      "accountRecordId": 10,
      "tenantRecordId": 1,
      "bundleId": "d1b329c7-7dcf-466c-aaca-47bff304dab0",
      "category": "BASE",
      "startDate": "2019-02-22T22:38:10.000Z",
      "bundleStartDate": "2019-02-22T22:38:10.000Z",
      "chargedThroughDate": "2019-03-22T23:35:14.000Z",
      "migrated": false,
      "tableName": "SUBSCRIPTIONS",
      "historyTableName": "SUBSCRIPTION_HISTORY"
    }
  }
]

Query Parameters

None.

Response

If successful, returns a status code of 200 and a list of audit logs.

Retrieve subscription event audit logs with history by subscription event id

Retrieve a list of audit log records showing changes to a subscription event. History information (a copy of the full subscription event object) is included with each record. The subscription resource contains the list of events associated with a subscription and the event id can be obtained from here.

Some examples:

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/subscriptions/events/{subscriptionEventId}/auditLogsWithHistory

Example Request:

curl  \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: application/json" \
    "http://localhost:8080/1.0/kb/subscriptions/events/9a1c85d5-beba-40c8-9268-f73e09c24007/auditLogsWithHistory"
import org.killbill.billing.client.api.gen.SubscriptionApi;
protected SubscriptionApi subscriptionApi;

UUID subscriptionEventId = UUID.fromString("b4b6f990-4456-4009-9e6c-9825a99a1f25");

List<AuditLog> eventAuditLog = subscriptionApi.getSubscriptionEventAuditLogsWithHistory(subscriptionEventId, requestOptions);
TODO
subscriptionApi = killbill.api.SubscriptionApi()

event_id = 'dc283026-5be0-4e47-8190-b62fb0c9e357'

auditlogs = subscriptionApi.get_subscription_event_audit_logs_with_history(event_id)
const api: killbill.SubscriptionApi = new killbill.SubscriptionApi(config);

const eventId = 'dc283026-5be0-4e47-8190-b62fb0c9e357';

const response: AxiosResponse<killbill.AuditLog[], any> = await api.getSubscriptionEventAuditLogsWithHistory(eventId);
$apiInstance = $client->getSubscriptionApi();

$eventId = "dc283026-5be0-4e47-8190-b62fb0c9e357";

$result = $apiInstance->getSubscriptionEventAuditLogsWithHistory($eventId);

Example Response:

[
  {
    "changeType": "INSERT",
    "changeDate": "2019-02-22T22:38:10.000Z",
    "objectType": "SUBSCRIPTION_EVENT",
    "objectId": "9a1c85d5-beba-40c8-9268-f73e09c24007",
    "changedBy": "admin",
    "reasonCode": null,
    "comments": null,
    "userToken": "1f03e074-dea1-45c5-aee3-c9464886f476",
    "history": {
      "id": null,
      "createdDate": "2019-02-22T22:38:10.000Z",
      "updatedDate": "2019-02-22T22:38:10.000Z",
      "recordId": 1358,
      "accountRecordId": 10,
      "tenantRecordId": 1,
      "totalOrdering": 0,
      "eventType": "API_USER",
      "userType": "CREATE",
      "effectiveDate": "2019-02-22T22:38:10.000Z",
      "subscriptionId": "70b6856e-6938-495f-9ae9-0a8ec0571c37",
      "planName": "foo-monthly",
      "phaseName": "foo-monthly-evergreen",
      "priceListName": "DEFAULT",
      "billingCycleDayLocal": 0,
      "isActive": true,
      "tableName": "SUBSCRIPTION_EVENTS",
      "historyTableName": "SUBSCRIPTION_EVENT_HISTORY",
      "active": true
    }
  }
]

Query Parameters

None.

Response

If successful, returns a status code of 200 and a list of audit logs with history.