Developers

The Kill Bill API, in Your Language

Everything in Kill Bill is an API call: catalog, customers, subscriptions, usage, invoices and payments. Call it from any language, with client libraries for six, or from an AI assistant through MCP.

Last updated: October 2026

Short answer

How do developers use Kill Bill?

Through a REST API with JSON over HTTP, on their own Kill Bill server. Each call carries a user and password plus a tenant API key and secret. Client libraries exist for Java, Ruby, Python, Go, PHP and JavaScript, Kill Bill posts events to your URL, and the aviate-mcp server lets AI assistants call the same API.
Style
REST, JSON over HTTP
Base path
/1.0/kb/ on your Kill Bill server
Authentication
User and password, plus a tenant API key and secret
Client libraries
Java, Ruby, Python, Go, PHP, JavaScript
Events
Push notifications to your URL, or a plugin
AI agents
aviate-mcp server, about 127 tools
Your first call

Create a Customer Account, in Six Languages

The same call in cURL and in each client library: create an account for John Doe, billed in US dollars.
curl -v \
     -X POST \
     -u admin:password \
     -H 'X-Killbill-ApiKey: bob' \
     -H 'X-Killbill-ApiSecret: lazar' \
     -H 'X-Killbill-CreatedBy: tutorial' \
     -H 'Content-Type: application/json' \
     -d '{ "name": "John Doe", "currency": "USD"}' \
     'http://127.0.0.1:8080/1.0/kb/accounts'
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.client.KillBillClientException;
import org.killbill.billing.client.KillBillHttpClient;
import org.killbill.billing.client.RequestOptions;
import org.killbill.billing.client.api.gen.AccountApi;
import org.killbill.billing.client.model.gen.Account;

KillBillHttpClient client = new KillBillHttpClient("http://127.0.0.1:8080",
                                                   "admin",
                                                   "password",
                                                   "bob",
                                                   "lazar");
AccountApi accountApi = new AccountApi(client);

Account body = new Account();
body.setName("John Doe");
body.setCurrency(Currency.USD);

RequestOptions requestOptions = RequestOptions.builder()
                                              .withCreatedBy("tutorial")
                                              .build();
Account account = accountApi.createAccount(body, requestOptions);
import killbill

killbill.configuration.base_uri = 'http://127.0.0.1:8080'
killbill.configuration.username = 'admin'
killbill.configuration.password = 'password'

account_api = killbill.api.AccountApi()
body = killbill.models.account.Account(name='John Doe', currency='USD')
account = account_api.create_account(body, 'tutorial', 'bob', 'lazar')
require 'killbill_client'

KillBillClient.url = 'http://127.0.0.1:8080'

options = {
  :username => 'admin',
  :password => 'password',
  :api_key => 'bob',
  :api_secret => 'lazar'
}

body = KillBillClient::Model::Account.new
body.name = 'John Doe'
body.currency = 'USD'

account = body.create('tutorial', nil, nil, options)
import (
	"context"
	"encoding/base64"
	"github.com/go-openapi/runtime"
	httptransport "github.com/go-openapi/runtime/client"
	"github.com/go-openapi/strfmt"
	"github.com/killbill/kbcli/kbclient"
	"github.com/killbill/kbcli/kbclient/account"
	"github.com/killbill/kbcli/kbmodel"
)

trp := httptransport.New("127.0.0.1:8080", "", nil)

authWriter := runtime.ClientAuthInfoWriterFunc(
	func(r runtime.ClientRequest, _ strfmt.Registry) error {
		encoded := base64.StdEncoding.EncodeToString([]byte("admin:password"))
		if err := r.SetHeaderParam("Authorization", "Basic "+encoded); err != nil {
			return err
		}
		if err := r.SetHeaderParam("X-KillBill-ApiKey", "bob"); err != nil {
			return err
		}
		if err := r.SetHeaderParam("X-KillBill-ApiSecret", "lazar"); err != nil {
			return err
		}
		return nil
	})

createdBy := "tutorial"
defaults := kbclient.KillbillDefaults{
	CreatedBy: &createdBy,
}

client := kbclient.New(trp, strfmt.Default, authWriter, defaults)
body := &kbmodel.Account{
	Name:     "John Doe",
	Currency: "USD",
}

newAccount, err := client.Account.CreateAccount(
	context.Background(),
	&account.CreateAccountParams{
		Body:                  body,
		ProcessLocationHeader: true,
	})
if err == nil {
	print(newAccount.GetPayload().AccountID)
}
require_once(__DIR__ . '/vendor/autoload.php');

$config = Killbill\Client\Swagger\Configuration::getDefaultConfiguration();
$config->setHost('http://127.0.0.1:8080')
       ->setUsername('admin')
       ->setPassword('password')
       ->setApiKey('X-Killbill-ApiKey', 'bob')
       ->setApiKey('X-Killbill-ApiSecret', 'lazar');

$accountApi = new Killbill\Client\Swagger\Api\AccountApi(null, $config);

$accountData = new Killbill\Client\Swagger\Model\Account();
$accountData->setName('John Doe');
$accountData->setCurrency('USD');

$account = $accountApi->createAccount($accountData, 'tutorial', NULL, NULL);

Examples from the API quick start, for a local Kill Bill with the default test credentials.

How a call works

Three Things Every Call Says

Who you are, which tenant you work in, and who made the change. The rest is plain JSON.
POST http://127.0.0.1:8080/1.0/kb/accounts
-u admin:password
X-Killbill-ApiKey: bob
X-Killbill-ApiSecret: lazar
X-Killbill-CreatedBy: tutorial
Content-Type: application/json
{ "name": "John Doe", "currency": "USD" }
Who you areA Kill Bill user, with basic authentication. Users and roles control what each one can do.
Which tenantAn API key and secret pick the tenant: a business unit, a brand or a test environment, each with its own data and settings.
Who made the changeEvery write records who did it, with an optional reason and comment, in the audit log.
A typical integration

Seven Calls From Catalog to Invoice

Most integrations follow the same path. Kill Bill then generates invoices and collects payments on its own, on schedule.
  1. OnceCreate a tenantPOST /1.0/kb/tenants
  2. OnceUpload your catalogPOST /1.0/kb/catalog/xml
  3. Per customerCreate an accountPOST /1.0/kb/accounts
  4. Per customerAdd a payment methodPOST /1.0/kb/accounts/{accountId}/paymentMethods
  5. Per customerSubscribe to a planPOST /1.0/kb/subscriptions
  6. Each periodRecord usagePOST /1.0/kb/usages
  7. Any timeRead invoicesGET /1.0/kb/accounts/{accountId}/invoices

To react to what happens next, such as an invoice created or a payment failed, register a URL for push notifications.

Client libraries

Client Libraries

Open source, under the Apache 2.0 license, on GitHub. Any other language can call the REST API directly.
LanguageRepositoryStatus
Javakillbill-client-javaUpdated with Kill Bill releases
Rubykillbill-client-rubyUpdated with Kill Bill releases
Pythonkillbill-client-pythonGenerated from the API definition
GokbcliGenerated from the API definition
PHPkillbill-client-phpGenerated from the API definition
JavaScript and Node.jskillbill-client-jsGenerated from the API definition
For AI agents

An MCP Server That Runs Next to Your Kill Bill

Ask an AI assistant to do billing work in plain English. The aviate-mcp server turns the request into Kill Bill and Aviate API calls.
Your AI assistant
Create a product with a monthly price and a usage component, subscribe a customer, record usage, and show me the invoices.
→
aviate-mcp, on your machine
kb_*Kill Bill API: accounts, subscriptions, invoices, payments, catalog, tags, custom fields, audit logs
aviate_*Aviate API: catalog, billing meters, wallets, coupons, usage
adminwhoami, list and switch deployments and tenants
→
Your Kill Bill
Kill BillCredentials stay with you. No hosted endpoint.

Read the announcement on the Kill Bill blog.

FAQs

Frequently Asked Questions

Does Kill Bill have a REST API?
Yes. Everything in Kill Bill is available through a REST API with JSON over HTTP, under /1.0/kb/ on your own Kill Bill server: tenants, catalog, accounts, payment methods, subscriptions, usage, invoices, payments, tags, custom fields and audit logs. Kaui, the admin UI, uses the same API.
How do I authenticate to the Kill Bill API?
Each call carries a Kill Bill user and password with basic authentication, and the API key and secret of the tenant in the X-Killbill-ApiKey and X-Killbill-ApiSecret headers. Calls that change data also carry X-Killbill-CreatedBy, which is recorded in the audit log.
Which programming languages have a Kill Bill client library?
Java, Ruby, Python, Go, PHP and JavaScript. The Java and Ruby clients are updated with Kill Bill releases. The others are generated from the API definition. Any language that can send HTTP requests can call the API directly.
Is there an OpenAPI or Swagger definition?
Yes. Kill Bill ships Swagger UI at /api.html on the server, where you can browse and try every call. The full reference with examples is at apidocs.killbill.io.
Does Kill Bill support webhooks?
Yes, through push notifications. Register a callback URL for a tenant, and Kill Bill sends each event to it by HTTP POST, with retries if your endpoint does not answer with a 2xx status. Plugins can also listen to every event inside Kill Bill.
Does Kill Bill have an MCP server for AI agents?
Yes. The aviate-mcp server exposes Kill Bill and Aviate APIs as about 127 tools for MCP clients such as AI assistants. It runs as a local process next to your Kill Bill, so your credentials never leave your environment.
How do the Aviate APIs differ from the Kill Bill API?
Aviate adds APIs for its modules, such as the catalog, metering, wallets and coupons, under /plugins/aviate-plugin/v1 on the same server. They use a JWT ID token as a Bearer token, which expires after about 60 minutes.
Can I try the API without installing anything?
Yes. The free Aviate sandbox gives you credentials for a cloud Kill Bill and Kaui, so you can make your first calls right away. You can also run Kill Bill locally with Docker.
Kill Bill logo

Make your first call today

Get sandbox credentials in the free Aviate sandbox, or run Kill Bill locally with Docker and follow the API quick start.