Tenant

Tenant Resource

Kill Bill has been designed from the ground up as a multi-tenant system, that is, one where multiple unrelated deployments can be hosted on the same physical system. Each deployment has its own separate configuration, catalog, and plugins, and of course its data set is kept entirely separate from the others. RBAC control allows different users/admin/apps to access zero, one or multiple tenants. This blog illustrates some interesting use cases. The Tenant resource allows the management of such tenants.

The attributes of the Tenant resource object are the following:

Name Type Generated by Description
tenantId string system UUID for this tenant
externalKey string system or user Optional external key provided by the client
apiKey string user The API key associated with the tenant
apiSecret string user The API secret associated with the tenant. This value is hashed and cannot be retrieved.
auditLogs array system Array of audit log records for this tenant

Note that the tenant itself has very few attributes, as most attributes belong to the individual accounts and related resources.

Tenant

These endpoints manage information that is maintained at the tenant level. Unless otherwise stated, the tenant is identified by its API key in the header.

Create a tenant

This API creates a new tenant.

Note: If you create a tenant using this API, it will not be recognized immediately by KAUI because KAUI will be unable to retrieve the apiSecret. To fix this, you should "create" the same tenant separately after logging into KAUI. This will not create another tenant, but it will synchronize KAUI with the one already created.

HTTP Request

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

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '{ "apiKey": "bob", "apiSecret": "lazar"}' \
    "http://127.0.0.1:8080/1.0/kb/tenants"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

UUID tenantId = null;
String externalKey = null;
String apiKey = "bob";
String apiSecret = "lazar";
List<AuditLog> EMPTY_AUDIT_LOGS = Collections.emptyList();

Tenant body = new Tenant(tenantId,
                         externalKey,
                         apiKey,
                         apiSecret,
                         EMPTY_AUDIT_LOGS);

tenantApi.createTenant(body, requestOptions);
tenant = KillBillClient::Model::Tenant.new
tenant.external_key = "demo_external_key"
tenant.api_key = "demo_api_key"
tenant.api_secret = "demo_api_secret"

use_global_default = true
user = "demo"
reason = nil
comment = nil

tenant.create(use_global_default,
              user,
              reason,
              comment,
              options)
tenantApi = killbill.api.TenantApi()

body = Tenant(api_key='demo_api_key', api_secret='demo_api_secret')

tenantApi.create_tenant(body, created_by='demo')
const api: killbill.TenantApi = new killbill.TenantApi(config);

const tenant: killbill.Tenant = {apiKey: `api_key`, apiSecret: `api_secret`};

api.createTenant(tenant, 'created-by', 'reason', 'comment');
$apiInstance = $client->getTenantApi();

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

$tenant = new Tenant();
$tenant->setApiKey('demo_api_key');
$tenant->setApiSecret('demo_api_secret');

$useGlobalDefault = false;

$result = $apiInstance->createTenant($tenant, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment, $useGlobalDefault);

Request Body

A JSON string representing a Tenant resource. The only parameters required are apiKey and apiSecret. The externalKey is optional and will be set to null if not supplied. The tenantId is generated by the system.

Query Parameters

Name Type Required Default Description
useGlobalDefault boolean false false If true, configure the tenant with a default catalog

Setting the useGlobalDefault parameter to true can be used for test purposes. This will configure the tenant with a default catalog, and therefore make it easy to quickly start playing with the apis. Note that in order to then upload a new custom catalog, one would need to invalidate the caches for this tenant.

Response

If successful, returns a status code of 201 and an empty body. In addition a Location parameter is returned in the header. This parameter gives the URL for the tenant, including the tenantId.

Retrieve a tenant by id

Retrieves a tenant resource, given its ID.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/tenants/{tenantId}

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: application/json" \
    "http://127.0.0.1:8080/1.0/kb/tenants/6907712e-e940-4033-8695-36894db128d3"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

UUID tenantId = UUID.fromString("6907712e-e940-4033-8695-36894db128d3");
tenantApi.getTenant(tenantId, requestOptions);
tenant_id = "ab5981c2-de14-43d6-a35b-a2ed0b28c746"

tenant = KillBillClient::Model::Tenant.find_by_id(tenant_id, options)
tenantApi = killbill.api.TenantApi()

tenant = tenantApi.get_tenant(tenant_id='1a723c1a-9287-459f-9e40-eca9f0fd213e')
const api: killbill.TenantApi = new killbill.TenantApi(config);

const id='9ab7db57-02a9-430c-bdfa-0a8c24d2e368'

const response: AxiosResponse<killbill.Tenant, any> = await api.getTenant(id);
$apiInstance = $client->getTenantApi();

$tenantid='9ab7db57-02a9-430c-bdfa-0a8c24d2e368';

$tenantdata = $apiInstance->getTenant($tenantid);

Example Response:

{
  "tenantId": "6907712e-e940-4033-8695-36894db128d3",
  "externalKey": "1532546166-326384",
  "apiKey": "bob",
  "apiSecret": null,
  "auditLogs": []
}

Query Parameters

none

Response

If successful, returns a status code of 200 and a tenant resource object. The apiSecret attribute is returned as null, since it cannot be retrieved.

Retrieve a tenant by its API key

Retrieves a tenant resource, given its apiKey. The apiKey is passed as a query parameter.

HTTP Request

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

Example Request:

curl -v \
    -u admin:password \
    -H "Accept: application/json" \
    "http://127.0.0.1:8080/1.0/kb/tenants?apiKey=bob"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String apiKey = "bob";

tenantApi.getTenantByApiKey(apiKey, requestOptions);
api_key = "demo_api_key"

tenant = KillBillClient::Model::Tenant.find_by_api_key(api_key, options)
tenantApi = killbill.api.TenantApi()

tenant = tenantApi.get_tenant_by_api_key(api_key='bob')
const api: killbill.TenantApi = new killbill.TenantApi(config);

const apiKey = 'bob'

const response: AxiosResponse<killbill.Tenant, any> = await api.getTenantByApiKey(apiKey);
$apiInstance = $client->getTenantApi();

$apikey='bob';

$tenantdata = $apiInstance->getTenantByApiKey($apikey);

Example Response:

{
  "tenantId": "6907712e-e940-4033-8695-36894db128d3",
  "externalKey": "1532546166-326384",
  "apiKey": "bob",
  "apiSecret": null,
  "auditLogs": []
}

Query Parameters

Name Type Required Default Description
apiKey string true none api key

Response

If successful, returns a status code of 200 and a tenant resource object. The apiSecret attribute is returned as null, since it cannot be retrieved.

Tenant Key-Value Pairs

These endpoints provide a mechanism to register and manage {key, value} pairs for a given tenant. This functionality is used internally by the system to keep track of all the per-tenant configuration, including system properties, plugin configuration, and others discussed below. In addition, you can add user keys to keep track of additional information that may be desired. For example, some global setting that would be accessible for all plugins could be stored here.

Add a per tenant user key/value

This API adds a key-value pair to the tenant database. If the key already exists, the new value is appended to the existing value. The key is given as a path parameter.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/tenants/userKeyValue/{keyName}

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/plain" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d "demo_value" \
    "http://127.0.0.1:8080/1.0/kb/tenants/userKeyValue/demo_key"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String keyName = "demo_key";
String body = "demo_value";
TenantKeyValue result = tenantApi.insertUserKeyValue(keyName, body, requestOptions);
user = "demo"
reason = nil
comment = nil

key_name = "demo_key"
key_value = "demo_value"

tenant_key_value = KillBillClient::Model::Tenant.upload_tenant_user_key_value(key_name,
                                                           key_value,
                                                           user,
                                                           reason,
                                                           comment,
                                                           options)
tenantApi = killbill.api.TenantApi()

key_name = 'demo_key'
body = 'demo_value'

tenantApi.insert_user_key_value(key_name, body, created_by='demo')
const key = 'demo_key';
const value = 'demo_value';

const api: killbill.TenantApi = new killbill.TenantApi(config);

api.insertUserKeyValue(value, key, 'created-by', 'reason', 'comment')
$apiInstance = $client->getTenantApi();

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

$keyName = "demo_key";
$body = "demo_value";

$result = $apiInstance->insertUserKeyValue($body, $xKillbillCreatedBy, $keyName, $xKillbillReason, $xKillbillComment);

Request Body

The body contains a single string representing the value.

Query Parameters

None.

Response

If successful, returns a status code of 201 and an empty body. In addition, a Location item is returned in the header giving the URL for this key-value pair.

Retrieve a per tenant user key value

Retrieves the value for a specified key, if it exists, from the tenant database. The key name is given as a path parameter.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/tenants/userKeyValue/{keyName}

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: application/json" \
    "http://127.0.0.1:8080/1.0/kb/tenants/userKeyValue/demo_key"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String keyName = "demo_key";

TenantKeyValue result = tenantApi.getUserKeyValue(keyName, requestOptions);
key_name = "demo_key"

tenant_key_value = KillBillClient::Model::Tenant.get_tenant_user_key_value(key_name, options)
tenantApi = killbill.api.TenantApi()

key_name = 'demo_key'

tenantKeyValue = tenantApi.get_user_key_value(key_name)
const api: killbill.TenantApi = new killbill.TenantApi(config);

const key = 'demo_key'

const response: AxiosResponse<killbill.TenantKeyValue, any> = await api.getUserKeyValue(key)
$apiInstance = $client->getTenantApi();

$keyName = "demo_key";

$result = $apiInstance->getUserKeyValue($keyName);

Example Response:

{
  "key": "demo_value",
  "values": [
    "demo_value",
    "demo_value"
  ]
}

Query Parameters

None.

Response

If successful, returns a status code of 200 and a tenant key value object. The key value object includes the key name and a JSON array containing the value, if any, or a comma-separated list of values. For example:

{ "key": "MYKEY", "values": [ "value1", "value2" ] }

If the key does not exist no error is signalled but the values list is empty.

Delete a per tenant user key/value

Deletes a key and its value, if it exists, from the tenant database. The key is given as a path parameter.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/tenants/userKeyValue/{keyName}

Example Request:

curl -v \
    -X DELETE \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    "http://127.0.0.1:8080/1.0/kb/tenants/userKeyValue/demo_key"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String keyName = "demo_key";

tenantApi.deleteUserKeyValue(keyName, requestOptions);
user = "demo"
reason = nil
comment = nil
key_name = "demo_key"

KillBillClient::Model::Tenant.delete_tenant_user_key_value(key_name,
                                                           user,
                                                           reason,
                                                           comment,
                                                           options)
tenantApi = killbill.api.TenantApi()

key_name = 'demo_key'

tenantApi.delete_user_key_value(key_name, created_by='demo')
const api: killbill.TenantApi = new killbill.TenantApi(config);

const key = 'demo_key'

api.deleteUserKeyValue(key, 'created-by', 'reason', 'comment')
$apiInstance = $client->getTenantApi();

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

$keyName = "demo_key"; 

$apiInstance->deleteUserKeyValue($keyName, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment);

Query Parameters

None.

Returns

If successful, returns a status code of 204 and an empty body. No error is signalled if the key does not exist.

Retrieve per tenant keys and values based on a key prefix

This API enables searching for existing keys based on a prefix of the key name. For example, a search string of "MYK" would match keys such as MYKEY1, MYKEY2, etc. The search string is given as a path parameter.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/tenants/uploadPerTenantConfig/{keyPrefix}/search

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: application/json" \
    "http://127.0.0.1:8080/1.0/kb/tenants/uploadPerTenantConfig/PER_TENANT/search"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String keyPrefix = "PER_TENANT";

TenantKeyValues result = tenantApi.getAllPluginConfiguration(keyPrefix, requestOptions);
key_prefix = "PER_TENANT"

tenant_key_values = KillBillClient::Model::Tenant.search_tenant_config(key_prefix, options)
tenantApi = killbill.api.TenantApi()

tenantKeyValues = tenantApi.get_all_plugin_configuration(key_prefix='PER_TENANT')
const api: killbill.TenantApi = new killbill.TenantApi(config);

const keyPrefix = 'PER_TENANT'

const response: AxiosResponse<killbill.TenantKeyValue, any> = await api.getAllPluginConfiguration(keyPrefix)
$keyPrefix = "PER_TENANT";

$result = $apiInstance->getAllPluginConfiguration($keyPrefix);

Example Response:

{
  "key": "PER_TENANT_CONFIG",
  "values": [
    "{org.killbill.invoice.sanitySafetyBoundEnabled:false}"
  ]
}

Query Parameters

None.

Response

If successful, returns a status code of 200 and a tenant key value object containing the key and values for any keys that match the search string.

Push Notifications

Push notifications are a convenient way to get notified about events from the system. One can register a callback, i.e, a valid URL that will be called whenever there is an event dispatched for this tenant. Note that this can result in a large number of calls; every time there is a state change for one of the Accounts in this tenant, the callback will be invoked.

In case of error, the system will retry the callback as defined by the system property org.killbill.billing.server.notifications.retries.

See push notification documentation here for further information.

Register a push notification

Register a callback URL for this tenant for push notifications. Inserts a key-value pair corresponding to the tenant where key name is PUSH_NOTIFICATION_CB and value is the URL of the push notification handler. The API sets the value of this key, replacing any previous value.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/tenants/registerNotificationCallback

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    'http://127.0.0.1:8080/1.0/kb/tenants/registerNotificationCallback?cb=http://demo/callmeback'
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String cb = "http://demo/callmeback";

TenantKeyValue result = tenantApi.registerPushNotificationCallback(cb, requestOptions);
cb = "http://demo/callmeback"
user = 'demo'
reason = ''
comment = ''

KillBillClient::Model::Tenant.register_push_notification(cb, user, reason, comment, options)
tenantApi = killbill.api.TenantApi()

tenantApi.register_push_notification_callback(created_by='demo', cb='http://demo/callmeback')
TODO
$apiInstance = $client->getTenantApi();

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

$cb = "http://demo/callmeback";

$result = $apiInstance->registerPushNotificationCallback($xKillbillCreatedBy, $cb, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
cb string true none callback URL to register

Response

If successful, returns a status code of 201 and an empty body. In addition, a Location item is returned in the header giving the URL for this callback.

Retrieve a registered push notification

Gets the push notification registered for this tenant, if any.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/tenants/registerNotificationCallback

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/tenants/registerNotificationCallback"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

TenantKeyValue result = tenantApi.getPushNotificationCallbacks(requestOptions);
result = KillBillClient::Model::Tenant.retrieve_push_notification(cb, options)
tenantApi = killbill.api.TenantApi()

tenantApi.get_push_notification_callbacks()
const api: killbill.TenantApi = new killbill.TenantApi(config);

const response: AxiosResponse<killbill.TenantKeyValue, any> = await api.getPushNotificationCallbacks()
$apiInstance = $client->getTenantApi();

$result = $apiInstance->getPushNotificationCallbacks();

Example Response:

{
  "key": "PUSH_NOTIFICATION_CB",
  "values": [
    "http://demo/callmeback"
  ]
}

Query Parameters

None.

Response

If successful, returns a status code of 200 and a tenant key value object for the key PUSH_NOTIFICATION_CB.

Delete a registered push notification

Deletes the registered callback URL, if any.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/tenants/registerNotificationCallback

Example Request:

curl -v \
    -X DELETE \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    "http://127.0.0.1:8080/1.0/kb/tenants/registerNotificationCallback"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

tenantApi.deletePushNotificationCallbacks(requestOptions);
user = 'demo'
reason = ''
comment = ''
KillBillClient::Model::Tenant.delete_push_notification(user, reason, comment, options)
tenantApi = killbill.api.TenantApi()

tenantApi.delete_push_notification_callbacks(created_by='demo')
const api: killbill.TenantApi = new killbill.TenantApi(config);

api.deletePushNotificationCallbacks('created-by', 'reason', 'comment')
$apiInstance = $client->getTenantApi();

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

$apiInstance->deletePushNotificationCallbacks($xKillbillCreatedBy, $xKillbillReason, $xKillbillComment);

Query Parameters

None.

Response

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

System Properties Configuration

These endpoints allow setting of some system properties on a per-tenant basis. Please refer to our configuartion guide to see what can be configured in the system. Some of the configuration can be overriden at the tenant level to allow for different behaviors.

Note that this is actually a special case of per-tenant key-value pairs; the key is "PER_TENANT_CONFIG" and the value is a comma-separated list of system properties with their values.

Add a per tenant system properties configuration

This API is used to set the value of specific system properties, overriding the system-wide values.

For example, in order to disable the invoice safety bound mechanism on a per-tenant level, this API could be used to set the per-tenant system property org.killbill.invoice.sanitySafetyBoundEnabled to false.

The API inserts a key-value pair corresponding to the tenant where key name is PER_TENANT_CONFIG and value is the system property to be set. It replaces any previous value.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/tenants/uploadPerTenantConfig

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/plain" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '{"org.killbill.invoice.sanitySafetyBoundEnabled":"false"}' \
    "http://127.0.0.1:8080/1.0/kb/tenants/uploadPerTenantConfig"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String body = "{'org.killbill.invoice.sanitySafetyBoundEnabled':'false'}";

TenantKeyValue result = tenantApi.uploadPerTenantConfiguration(body, requestOptions);
configuration = {"org.killbill.invoice.sanitySafetyBoundEnabled": false}
user = 'demo'
reason = ''
comment = ''
result = KillBillClient::Model::Tenant.add_system_configuration(configuration, user, reason, comment, options)
tenantApi = killbill.api.TenantApi()

body = '{"org.killbill.invoice.sanitySafetyBoundEnabled":"false"}'

tenantApi.upload_per_tenant_configuration(body, created_by='demo')
const body = '{"org.killbill.invoice.sanitySafetyBoundEnabled":"false"}';

const api: killbill.TenantApi = new killbill.TenantApi(config);

api.uploadPerTenantConfiguration(body, 'created-by', 'reason', 'comment')
$apiInstance = $client->getTenantApi();

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

$body = "{'org.killbill.invoice.sanitySafetyBoundEnabled':'false'}";

$result = $apiInstance->uploadPerTenantConfiguration($body, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment);

Request Body

A JSON string representing the per-tenant system property and its value.

Query Parameters

None.

Response

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

Retrieve a per tenant system properties configuration

Retrieves the per-tenant system property settings, which are given as the value of the key PER_TENANT_CONFIG.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/tenants/uploadPerTenantConfig

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: application/json" \
    "http://127.0.0.1:8080/1.0/kb/tenants/uploadPerTenantConfig"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

TenantKeyValue result = tenantApi.getPerTenantConfiguration(requestOptions);
result = KillBillClient::Model::Tenant.retrieve_system_configurations(options)
tenantApi = killbill.api.TenantApi()

tenantKeyValue =  tenantApi.get_per_tenant_configuration()
const api: killbill.TenantApi = new killbill.TenantApi(config);

const response: AxiosResponse<killbill.TenantKeyValue, any> = await api.getPerTenantConfiguration()
$apiInstance = $client->getTenantApi();

$result = $apiInstance->getPerTenantConfiguration();

Example Response:

{
  "key": "PER_TENANT_CONFIG",
  "values": [
    "{org.killbill.invoice.sanitySafetyBoundEnabled:false}"
  ]
}

Query Parameters

None.

Response

If successful, returns a status code of 200 and a tenant key value object for the key PER_TENANT_CONFIG.

Delete a per tenant system properties configuration

Deletes any current per tenant system properties configuration parameters, which are given as the values of the PER_TENANT_CONFIG key.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/tenants/uploadPerTenantConfig

Example Request:

curl -v \
    -X DELETE \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    "http://127.0.0.1:8080/1.0/kb/tenants/uploadPerTenantConfig"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

tenantApi.deletePerTenantConfiguration(requestOptions);
user = 'demo'
reason = ''
comment = ''
KillBillClient::Model::Tenant.delete_system_configurations(user, reason, comment, options)
tenantApi = killbill.api.TenantApi()

tenantApi.delete_per_tenant_configuration(created_by='demo')
const api: killbill.TenantApi = new killbill.TenantApi(config);

api.deletePerTenantConfiguration('created-by', 'reason', 'comment')
$apiInstance = $client->getTenantApi();

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

$apiInstance->deletePerTenantConfiguration($xKillbillCreatedBy, $xKillbillReason, $xKillbillComment);

Query Parameters

None.

Response

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

Plugin Configuration

Plugins also support configuration on a per-tenant level. Please refer to our plugin configuration manual for more details.

An example of the use of such per-tenant properties is to configure a payment plugin with different API keys, one set of keys for each tenant. This allows for a true multi-tenant deployment where plugins have different configuration based on the tenant in which they operate.

Upon adding or deleting a new per-tenant plugin configuration, the system will generate a TENANT_CONFIG_CHANGE/TENANT_CONFIG_DELETION event, which can be handled in the plugin to refresh its configuration. In multi-node scenarios, events will be dispatched on each node, that is, on each plugin instance so they end up with a consistent view. A lot of the logic to handle configuration update has been implemented in our plugin framework).

As with the system properties configuration, this is actually a special case of per-tenant key-value pairs. The following endpoints provide the ability to configure plugins on a per-tenant level.

Add a per tenant configuration for a plugin

Adds a per tenant key-value pair for the specified plugin. The plugin name is given as a path parameter. The API internally inserts a key-value pair corresponding to the tenant with key name=PLUGIN_CONFIG_*plugin* where plugin is the plugin name. It replaces any previous value.

The value string uploaded is plugin dependent but typically consists of key/value properties, or well formatted yml or a properties file.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginConfig/{pluginName}

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/plain" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d @./config.properties \
    "http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginConfig/demo_plugin"

OR 

curl -v \
     -X POST \
     -u admin:password \
     -H 'X-Killbill-ApiKey: bob' \
     -H 'X-Killbill-ApiSecret: lazar' \
     -H 'X-Killbill-CreatedBy: admin' \
     -H 'Content-Type: text/plain' \
     -d 'org.killbill.billing.plugin.avatax.url=XXX
org.killbill.billing.plugin.avatax.accountId=YYY
org.killbill.billing.plugin.avatax.licenseKey=ZZZ' \
     http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginConfig/killbill-avatax
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String pluginName = "PLUGIN_FOO";
String pluginConfig = "plugin configuration string";

TenantKeyValue result = tenantApi.uploadPluginConfiguration(pluginName, pluginConfig, requestOptions);
plugin_name = "demo_plugin"
plugin_config = "tenant_config"
user = "demo"
reason = nil
comment = nil

tenant_key_value = KillBillClient::Model::Tenant.upload_tenant_plugin_config(plugin_name,
                                                          plugin_config,
                                                          user,
                                                          reason,
                                                          comment,
                                                          options)
tenantApi = killbill.api.TenantApi()

plugin_name = 'demo_plugin'
body = 'tenant_config'

tenantApi.upload_plugin_configuration(plugin_name, body, created_by='demo')
const api: killbill.TenantApi = new killbill.TenantApi(config);

const plugin_name = 'demo_plugin';
const body = 'tenant_config'

api.uploadPluginConfiguration(body, plugin_name, 'created-by', 'reason', 'comment')
$apiInstance = $client->getTenantApi();

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

$pluginName = "demo_plugin";
$body = "tenant_config";

$result = $apiInstance->uploadPluginConfiguration($body, $xKillbillCreatedBy, $pluginName, $xKillbillReason, $xKillbillComment);

Request Body

The request body can be specified as a JSON string consisting of the key-value pairs for the plugin configuration. Alternatively, the plugin configuration can be specified in a yml or properties file and its path can be specified.

Query Parameters

None.

Response

If successful, returns a status code of 201 and an empty body. A Location header is also returned giving the URL of the key-value pair.

Retrieve a per tenant configuration for a plugin

Gets the per tenant configuration value string for a specified plugin. The plugin name is given as a path parameter.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginConfig/{pluginName}

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: application/json" \
    "http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginConfig/demo_plugin"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

final String pluginName = "PLUGIN_FOO";

final TenantKeyValue result = tenantApi.getPluginConfiguration(pluginName, requestOptions);
plugin_name = "demo_plugin"

tenant_key_value = KillBillClient::Model::Tenant.get_tenant_plugin_config(plugin_name, options)
tenantApi = killbill.api.TenantApi()

plugin_name = 'demo_plugin'

tenantKeyValue = tenantApi.get_plugin_configuration(plugin_name)
const api: killbill.TenantApi = new killbill.TenantApi(config);

const plugin_name = 'demo_plugin';

const response: AxiosResponse<killbill.TenantKeyValue, any> = await api.getPluginConfiguration(plugin_name)
$apiInstance = $client->getTenantApi();

$pluginName = "demo_plugin";

$result = $apiInstance->getPluginConfiguration($pluginName);

Example Response:

{
  "key": "PLUGIN_CONFIG_demo_plugin",
  "values": [
    "tenant_config"
  ]
}

Query Parameters

None.

Response

If successful, returns a status code of 200 and a tenant key value object for the key PLUGIN_CONFIG_*plugin*.

Delete a per tenant configuration for a plugin

Deletes the per tenant plugin configuration value for the appropriate key. The plugin name is given as a path parameter.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginConfig/{pluginName}

Example Request:

curl -v \
    -X DELETE \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    "http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginConfig/demo_plugin"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

final String pluginName = "PLUGIN_FOO";

tenantApi.deletePluginConfiguration(pluginName, requestOptions);
user = "demo"
reason = nil
comment = nil

plugin_name = "demo_plugin"

KillBillClient::Model::Tenant.delete_tenant_plugin_config(plugin_name,
                                                          user,
                                                          reason,
                                                          comment,
                                                          options)
tenantApi = killbill.api.TenantApi()

plugin_name = 'demo_plugin'

tenantApi.delete_plugin_configuration(plugin_name, created_by='demo')
const api: killbill.TenantApi = new killbill.TenantApi(config);

const plugin_name = 'demo_plugin';

api.deletePluginConfiguration(plugin_name, 'created-by', 'reason', 'comment')
$apiInstance = $client->getTenantApi();

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

$pluginName = "demo_plugin";

$apiInstance->deletePluginConfiguration($pluginName, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment);

Query Parameters

None.

Returns

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

Payment State Machines

This is a somewhat advanced use case to override the default internal payment state machine within Kill Bill. Please refer to our payment manual for more details about payment states.

The endpoints below allow you to override such state machines on a per-tenant level.

Add a per tenant payment state machine for a plugin

Adds a per tenant key-value pair for the specified plugin. The plugin name is given as a path parameter. The key name is PLUGIN_PAYMENT_STATE_MACHINE_*plugin* where plugin is the payment plugin name. The API sets the value of this key, replacing any previous value.

The state machine is defined in an XML file. The complete XML file becomes the value of the key.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginPaymentStateMachineConfig/{pluginName}

Request Body

The request body can be specified as an XML string. Alternatively, the path of the XML file can be specified.

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/plain" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '@SimplePaymentStates.xml' \
    "http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginPaymentStateMachineConfig/demo_plugin"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String pluginName = "demo_plugin";
String stateMachineConfig = "<xml>..</xml>";

TenantKeyValue result = tenantApi.uploadPluginPaymentStateMachineConfig(pluginName,
                                                                        stateMachineConfig,
                                                                        requestOptions);
plugin_name = "demo_plugin";
state_machine_config = "<xml>..</xml>";
user = 'demo'
reason = ''
comment = ''

KillBillClient::Model::Tenant.add_payment_state_machine(plugin_name, state_machine_config, user, reason, comment, options)
tenantApi = killbill.api.TenantApi()

plugin_name = 'demo_plugin'
body = '<xml>..</xml>'

tenantApi.upload_plugin_payment_state_machine_config(plugin_name, body, created_by='demo')
const api: killbill.TenantApi = new killbill.TenantApi(config);

const plugin_name = 'demo_plugin';
const body = '<xml>..</xml>'

api.uploadPluginPaymentStateMachineConfig(body, plugin_name, 'created-by', 'reason', 'comment')
$apiInstance = $client->getTenantApi();

$pluginName = "demo_plugin";
$body = "<xml>..</xml>";

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

$result = $apiInstance->uploadPluginPaymentStateMachineConfig($body, $xKillbillCreatedBy, $pluginName, $xKillbillReason, $xKillbillComment);

Query Parameters

None.

Response

If successful, returns a status code of 201 and an empty body. In addition, a Location item is returned in the header giving the URL for the payment state machine.

Retrieve a per tenant payment state machine for a plugin

Retrieves the complete XML file corresponding to the payment state machine for the specified plugin if it exists.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginPaymentStateMachineConfig/{pluginName}

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: application/json" \
    "http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginPaymentStateMachineConfig/demo_plugin"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String pluginName = "demo_plugin";

TenantKeyValue result = tenantApi.getPluginPaymentStateMachineConfig(pluginName, requestOptions);
plugin_name = "demo_plugin";

result = KillBillClient::Model::Tenant.retrieve_payment_state_machine(plugin_name, options)
tenantApi = killbill.api.TenantApi()

plugin_name = 'demo_plugin'

tenantKeyValue = tenantApi.get_plugin_payment_state_machine_config(plugin_name)
const api: killbill.TenantApi = new killbill.TenantApi(config);

const plugin_name = 'demo_plugin';

const response: AxiosResponse<killbill.TenantKeyValue, any> = await api.getPluginPaymentStateMachineConfig(plugin_name)
$apiInstance = $client->getTenantApi();

$pluginName = "demo_plugin";

$result = $apiInstance->getPluginPaymentStateMachineConfig($pluginName);

Example Response:

{
  "key": "PLUGIN_PAYMENT_STATE_MACHINE_demo_plugin",
  "values": [<?xml version="1.0" encoding="UTF-8"?>

    <stateMachineConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xsi:noNamespaceSchemaLocation="StateMachineConfig.xsd">

        <stateMachines>
            <stateMachine name="BIG_BANG">
                <states>
                    <state name="BIG_BANG_INIT"/>
                </states>
                <transitions>
                    <transition>
                        <initialState>BIG_BANG_INIT</initialState>
                        <operation>OP_DUMMY</operation>
                        <operationResult>SUCCESS</operationResult>
                        <finalState>BIG_BANG_INIT</finalState>
                    </transition>
                </transitions>
                <operations>
                    <operation name="OP_DUMMY"/>
                </operations>
            </stateMachine>
            <stateMachine name="AUTHORIZE">
                <states>
                    <state name="AUTH_INIT"/>
                    <state name="AUTH_SUCCESS"/>
                    <state name="AUTH_FAILED"/>
                    <state name="AUTH_ERRORED"/>
                </states>
                <transitions>
                    <transition>
                        <initialState>AUTH_INIT</initialState>
                        <operation>OP_AUTHORIZE</operation>
                        <operationResult>SUCCESS</operationResult>
                        <finalState>AUTH_SUCCESS</finalState>
                    </transition>
                    <transition>
                        <initialState>AUTH_INIT</initialState>
                        <operation>OP_AUTHORIZE</operation>
                        <operationResult>FAILURE</operationResult>
                        <finalState>AUTH_FAILED</finalState>
                    </transition>
                    <transition>
                        <initialState>AUTH_INIT</initialState>
                        <operation>OP_AUTHORIZE</operation>
                        <operationResult>EXCEPTION</operationResult>
                        <finalState>AUTH_ERRORED</finalState>
                    </transition>
                </transitions>
                <operations>
                    <operation name="OP_AUTHORIZE"/>
                </operations>
            </stateMachine>
        </stateMachines>

        <linkStateMachines>
            <linkStateMachine>
                <initialStateMachine>BIG_BANG</initialStateMachine>
                <initialState>BIG_BANG_INIT</initialState>
                <finalStateMachine>AUTHORIZE</finalStateMachine>
                <finalState>AUTH_INIT</finalState>
            </linkStateMachine>
        </linkStateMachines>
    </stateMachineConfig>
    ]
}

Query Parameters

None.

Response

If successful, returns a status code of 200 and a key value object for the key PLUGIN_PAYMENT_STATE_MACHINE_*plugin*.

Delete a per tenant payment state machine for a plugin

Deletes the payment state machine for the specified plugin for this tenant. The plugin reverts to the default payment state machine.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginPaymentStateMachineConfig/{pluginName}

Example Request:

curl -v \
    -X DELETE \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    "http://localhost:8080/1.0/kb/tenants/uploadPluginPaymentStateMachineConfig/demo_plugin"
import org.killbill.billing.client.api.gen.TenantApi;
protected TenantApi tenantApi;

String pluginName = "demo_plugin";

tenantApi.deletePluginPaymentStateMachineConfig(pluginName, requestOptions);
plugin_name = "demo_plugin"
user = 'demo'
reason = ''
comment = ''

KillBillClient::Model::Tenant.delete_payment_state_machine(plugin_name, user, reason, comment, options)
tenantApi = killbill.api.TenantApi()

plugin_name = 'demo_plugin'

tenantApi.delete_plugin_payment_state_machine_config(plugin_name, created_by='demo')
const api: killbill.TenantApi = new killbill.TenantApi(config);

const plugin_name = 'demo_plugin';

api.deletePluginPaymentStateMachineConfig(plugin_name, 'created-by', 'reason', 'comment')
$apiInstance = $client->getTenantApi();

$pluginName = "demo_plugin";

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

$apiInstance->deletePluginPaymentStateMachineConfig($pluginName, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment);

Query Parameters

None.

Returns

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