Invoice

An invoice is a bill provided to a customer for charges that are payable on the customer's account. A single invoice consolidates charges for all subscriptions held by that customer for a specified time period. Invoices may be set to be paid automatically, or may be paid manually by the customer.

An invoice can be generated manually if there are any outstanding charges. In addition, charges can be explicitly added that will also result in an invoice being generated. Invoices can also be automatically generated by the system when there are existing active subscriptions for the Account. In the latter case, the targetDate will determine up to which point to invoice, and the billing mode (IN_ADVANCE or IN_ARREAR) will determine which period to charge for.

An invoice can have one of the following status values: DRAFT, COMMITTED, or VOID.

Invoice Resource

An Invoice resource represents an invoice associated with a specific account. The attributes contained in this resource are the following:

Name Type Generated by Description
invoiceId string system UUID for the invoice
accountId string system UUID for the account
amount number user or system Sum of all item amounts
currency string user or system Currency associated with the account
status string system Status of the invoice: DRAFT, COMMITTED or VOID
creditAdj number system Invoice credit (amount that we owe to the customer). It is calculated as the sum of CBA_ADJ invoice items
refundAdj number system Refund amount associated with an invoice. It is calculated as the sum of all invoice payment amounts of type REFUND and CHARGED_BACK.
invoiceDate date system Date when this invoice was generated
targetDate date user or system Date up to which the account has been invoiced
invoiceNumber number system Invoice number
balance number system Invoice balance (amount that a customer owes as part of an invoice). At a high level, it is calculated as the sum of all item amounts minus the payment amount. See Invoice Balance for further details.
bundleKeys list system List of bundles invoiced. Deprecated.
credits list system List of credits associated with this invoice. Deprecated.
items list system List of invoice items on this invoice. See InvoiceItem resource.
trackingIds list user List of usage tracking ids associated with this invoice
isParentInvoice boolean system If true, this invoice is the parent in the hierarchical model
parentInvoiceId string system In the hierarchical model, UUID of the parent invoice
parentAccountId string system In the hierarchical model, UUID of the parent account
auditLogs array system Array of audit log records for this invoice

InvoiceDryRun Resource

An InvoiceDryRun object encapsulates parameters that can be used to generate an invoice preview. Such an invoice preview can be generated to determine what would be in the invoice scheduled on a certain date, or if certain changes are made. A dry run has no actual effect on the system. The attributes contained in this resource are the following:

Name Type Generated by Description
dryRunType string user Category for this dry run (see notes below).
dryRunAction string user Action on which the dry run should be based, if any (see notes below). Applicable only for dryRunType=SUBSCRIPTION_ACTION.
phaseType string user Type of the plan phase (see notes below).
productName string user Name of the product subscribed
productCategory string user Product category (see notes below)
billingPeriod string user Billing period (see notes below)
priceListName string user Name of the applicable price list
subscriptiontId string system UUID for a subscription. If specified, only this subscription is used for the dry run
bundleId string system UUID for a bundle. If specified, only this subscription is used for the dry run
effectiveDate date user The date the change takes effect
billingPolicy string user The billing policy (see notes below)
priceOverrides list user List of prices if this subscription has price overrides
planName string user Name of the plan subscribed

dryRunType: Possible values are:

dryRunAction: Possible values are: START_BILLING, CHANGE (of Plan), or STOP_BILLING

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

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. See BillingPeriod.

billingPolicy: Possible values are START_OF_TERM, END_OF_TERM, or IMMEDIATE

Note that either the planName or a combination of productName, productCategory and billingPeriod needs to be specified for the START_BILLING, CHANGE dryRunAction.

Invoice

These endpoints provide basic operations on invoices.

Trigger an invoice run

Create an invoice run for the associated account. This may result in the creation of a new invoice if there is anything to invoice for, or nothing, if the account is up to date. If an invoice is created, all necessary attributes are determined by the system.

Also refer to our subscription manual for more examples

HTTP Request

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

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/invoices?accountId=29fd0a00-f08b-4886-849b-3f4b98c8df27"  
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID accountId = UUID.fromString("34a65013-2dd1-480e-b4b8-7999bb15ebce");
LocalDate targetDate = LocalDate.parse("2023-07-15");
Map<String, String> NULL_PLUGIN_PROPERTIES = null;

Invoice invoice = invoiceApi.createFutureInvoice(accountId, targetDate, NULL_PLUGIN_PROPERTIES, requestOptions);
user = "demo"
reason = nil
comment = nil

account_id = "3ee3aa82-1d45-4bbc-b36b-74d628e095d0"
target_date = "2024-12-05"

KillBillClient::Model::Invoice.trigger_invoice(account_id, 
                                               target_date, 
                                               user, 
                                               reason, 
                                               comment, 
                                               options)
invoiceApi = killbill.api.InvoiceApi()

account_id = 'bdbed417-a84b-4303-958c-b88a36807416'
target_date = datetime.date(2023, 10, 20)

invoiceApi.create_future_invoice(account_id,
                                 target_date=target_date,
                                 created_by='demo',
                                 reason='reason',
                                 comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const accountId = 'b462d167-d9bc-459a-bdb7-23ebf99f5b76';
const targetDate = '2023-10-21';

api.createFutureInvoice(accountId, 'created_by', targetDate);
$apiInstance = $client->getInvoiceApi();

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

$accountId = "d7ec4174-ab07-4e25-a917-ad020b755917";
$targetDate = new \DateTime("2023-10-21");
$pluginProperty = array("pluginProperty_example");

$result = $apiInstance->createFutureInvoice($accountId, $xKillbillCreatedBy, $targetDate, $pluginProperty, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
accountId string yes none account id
targetDate string no current date target date (date up to which the account should be invoiced)
pluginProperty array of strings no omit list of plugin properties, if any. Should be in the format key%3Dvalue

Response

If successful, returns a status code of 201 and an empty body. A location item is also returned in the header, giving the UUID of the generated invoice (if any). If there is nothing to invoice for, returns a 404 status code.

Create a migration invoice

This endpoint is used to insert existing invoices that are being migrated from either a third party system or an in-house billing system into Kill Bill.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/migration/{accountId}

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '[ { "invoiceItemId": "f38505c9-d673-4f0b-b7d4-9125cac2a567", "invoiceId": "f38505c9-d673-4f0b-b7d4-9125cac2a567", "linkedInvoiceItemId": "f38505c9-d673-4f0b-b7d4-9125cac2a567", "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d", "itemType": "EXTERNAL_CHARGE", "amount": 10, "rate": 0, "currency": "USD" }]' \
    "http://127.0.0.1:8080/1.0/kb/invoices/migration/2ad52f53-85ae-408a-9879-32a7e59dd03d"  
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID accountId = UUID.fromString("fe1a6f86-9ec5-4ac3-8d39-15f024cc8339");

BigDecimal chargeAmount = BigDecimal.TEN;
InvoiceItem externalCharge = new InvoiceItem();
externalCharge.setStartDate(new LocalDate());
externalCharge.setAccountId(accountId);
externalCharge.setAmount(chargeAmount);
externalCharge.setItemType(InvoiceItemType.EXTERNAL_CHARGE);
externalCharge.setCurrency(Currency.USD);
InvoiceItems inputInvoice = new InvoiceItems();
inputInvoice.add(externalCharge);

LocalDate targetDate = null;

Invoice migrationInvoice = invoiceApi.createMigrationInvoice(accountId, 
                                                             inputInvoice, 
                                                             targetDate,
                                                             requestOptions);
user = "demo"
reason = nil
comment = nil

account_id = "3a949187-a2a0-46b5-8720-fff8b12eabff"
target_date = "2018-03-15"

invoice_item = KillBillClient::Model::InvoiceItem.new
invoice_item.item_type = "EXTERNAL_CHARGE"
invoice_item.amount = 50
invoice_items = [invoice_item]

KillBillClient::Model::Invoice.create_migration_invoice(account_id,
                                                        invoice_items,
                                                        target_date,
                                                        user,
                                                        reason,
                                                        comment,
                                                        options)
invoiceApi = killbill.api.InvoiceApi()

account_id = 'bdbed417-a84b-4303-958c-b88a36807416'
body = InvoiceItem(account_id=account_id,
                   amount=50.0,
                   currency='USD',
                   item_type='EXTERNAL_CHARGE',
                   description='Migration item')

invoiceApi.create_migration_invoice(account_id,
                                    [body],
                                    created_by='demo',
                                    reason='reason',
                                    comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const accountId = 'b462d167-d9bc-459a-bdb7-23ebf99f5b76';
const item: InvoiceItem = {amount: 10, itemType: "EXTERNAL_CHARGE",description:"a migration item"};
const items = [item];

api.createMigrationInvoice(items, accountId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$item = new InvoiceItem();
$item -> setAmount(100);
$item -> setItemType("EXTERNAL_CHARGE");
$item -> setDescription("migration item");
$body = array($item);

$accountId = "f547bda2-ad09-4e79-84c3-9759939496dd";
$targetDate = NULL;

$result = $apiInstance->createMigrationInvoice($body, $xKillbillCreatedBy, $accountId, $xKillbillReason, $xKillbillComment, $targetDate);

Request Body

A List of invoice item resource objects with all fields filled in representing the invoice to be migrated. At least the itemType and amount fields need to be specified. If multiple invoice items are specified, a single invoice is created with all the invoice items.

Query Parameters

Name Type Required Default Description
targetDate string no current date target date

Response

If successful, returns a status code of 201 and an empty body. A location item is also returned in the header, giving the UUID of the generated invoice (if any).

Create external charge(s)

Create a charge for a given account. This will result in the creation of a new invoice.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/charges/{accountId}

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '[ { "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d", "description": "My charge", "amount": 50, "currency": "USD" }]'    \
    "http://127.0.0.1:8080/1.0/kb/invoices/charges/2ad52f53-85ae-408a-9879-32a7e59dd03d"
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID accountId = UUID.fromString("616789aa-4004-4681-b38c-b95871d534fc");

InvoiceItem externalCharge = new InvoiceItem();
externalCharge.setAccountId(accountId);
externalCharge.setAmount(BigDecimal.TEN);
externalCharge.setDescription("My charge");

InvoiceItems externalCharges = new InvoiceItems();
externalCharges.add(externalCharge);

LocalDate requestedDate = null;
Map<String, String> pluginProperty = null;
Boolean autoCommit = true;

List<InvoiceItem> createdExternalCharges = invoiceApi.createExternalCharges(accountId, 
                                                                            externalCharges, 
                                                                            requestedDate,
                                                                            autoCommit,
                                                                            pluginProperty, 
                                                                            requestOptions);
user = "demo"
reason = nil
comment = nil

invoice_item             = KillBillClient::Model::InvoiceItem.new()
invoice_item.account_id  = "83e5e82d-fe72-4873-9b8b-946f4d250b0d"
invoice_item.amount      = '50.0'
invoice_item.currency    = 'USD'
invoice_item.description = 'My charge'

auto_commit = true

invoice_item = invoice_item.create(auto_commit, 
                    user, 
                    reason, 
                    comment, 
                    options)
invoiceApi = killbill.api.InvoiceApi()

account_id = 'bdbed417-a84b-4303-958c-b88a36807416'
body = InvoiceItem(account_id=account_id,
                   amount=50.0,
                   currency='USD',
                   description='External charge')

invoice_item = invoiceApi.create_external_charges(account_id,
                                   [body],
                                   auto_commit=True,
                                   created_by='demo',
                                   reason='reason',
                                   comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const accountId = 'b462d167-d9bc-459a-bdb7-23ebf99f5b76';
const item: InvoiceItem = {amount: 10, itemType: "EXTERNAL_CHARGE",description:"external charge"};
const items = [item];

const response: AxiosResponse<killbill.InvoiceItem, any> = await api.createExternalCharges(items, accountId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$item = new InvoiceItem();
$item -> setAmount(100);
$item -> setItemType("EXTERNAL_CHARGE");
$item -> setDescription("external charge item");
$body = array($item);

$accountId = "f547bda2-ad09-4e79-84c3-9759939496dd";
$requestedDate = new \DateTime("2023-09-21");
$autoCommit = false;
$pluginProperty = array("pluginProperty_example");

$result = $apiInstance->createExternalCharges($body, $xKillbillCreatedBy, $accountId, $xKillbillReason, $xKillbillComment, $requestedDate, $autoCommit, $pluginProperty);

Example Response:

[
  {
    "invoiceItemId": "3aaadeeb-5ffe-4226-a8b6-57723f1f8c12",
    "invoiceId": "c6fe2246-62e2-450d-b9fc-a27003771535",
    "linkedInvoiceItemId": null,
    "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d",
    "childAccountId": null,
    "bundleId": null,
    "subscriptionId": null,
    "productName": null,
    "planName": null,
    "phaseName": null,
    "usageName": null,
    "prettyProductName": null,
    "prettyPlanName": null,
    "prettyPhaseName": null,
    "prettyUsageName": null,
    "itemType": "EXTERNAL_CHARGE",
    "description": "My charge",
    "startDate": "2018-07-20",
    "endDate": null,
    "amount": 50,
    "rate": null,
    "currency": "USD",
    "quantity": null,
    "itemDetails": null,
    "catalogEffectiveDate":null,
    "childItems": null,
    "auditLogs": []
  }
]

Request Body

A List of invoice item resource objects with at least the amount attribute populated. If multiple invoice items are specified, a single invoice is created with all the invoice items.

Query Parameters

Name Type Required Default Description
requestedDate string no current date requested date
autoCommit boolean no false If true, the resulting invoice should be COMMITTED.
pluginProperty array of strings no omit list of plugin properties, if any. Should be in the format key%3Dvalue

Response

If successful, returns a status code of 201 and an invoice item object.

Create tax items

Normally, tax items are added to an invoice by a plugin, which intercepts the invoice during its creation and adds the required tax items on the fly. However, sometimes you may want to add tax items directly. This API adds a tax item to an account, which will result in the creation of a new invoice. Also, it is worth noting, that the tax items are not linked to any existing invoiceItems. Consequently, specifying fields like linkedInvoiceItemId, subscriptionId while creating the tax item has no effect. These fields do not get saved on the database and will not be returned in subsequent GET requests.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/taxes/{accountId}

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '[ { "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d", "amount": 50, "currency": "USD" }]' \
    "http://127.0.0.1:8080/1.0/kb/invoices/taxes/2ad52f53-85ae-408a-9879-32a7e59dd03d"
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID accountId = UUID.fromString("eb36c64c-b575-4538-b26f-a89c473984da");
UUID bundleId = UUID.fromString("28723cec-5510-49be-9e87-3a36d246f25e");

InvoiceItem taxItem = new InvoiceItem();
taxItem.setAccountId(accountId);
taxItem.setAmount(BigDecimal.TEN);
taxItem.setCurrency(Currency.USD);
taxItem.setBundleId(bundleId);
final InvoiceItems input = new InvoiceItems();
input.add(taxItem);

Boolean autoCommit = true;
LocalDate requestedDate = null;
Map<String, String> pluginProperty = null;

List<InvoiceItem> createdTaxItems = invoiceApi.createTaxItems(accountId, 
                                                                     input,
                                                                     autoCommit,
                                                                     requestedDate,
                                                                     pluginProperty,
                                                                     requestOptions);
user = "demo"
reason = nil
comment = nil

invoice_item             = KillBillClient::Model::InvoiceItem.new()
invoice_item.account_id  = "3a949187-a2a0-46b5-8720-fff8b12eabff"
invoice_item.amount      = '50.0'
invoice_item.currency    = 'USD'
invoice_item.description = 'Tax item'

auto_commit = true

invoice_item = invoice_item.create_tax_item(auto_commit,
                              user,
                              reason,
                              comment,
                              options)
invoiceApi = killbill.api.InvoiceApi()

account_id = 'bdbed417-a84b-4303-958c-b88a36807416'
body = InvoiceItem(account_id=account_id,
                   amount=50.0,
                   currency='USD',
                   description='Tax item')

invoice_item = invoiceApi.create_tax_items(account_id,
                            [body],
                            auto_commit=True,
                            created_by='demo',
                            reason='reason',
                            comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const accountId = 'b462d167-d9bc-459a-bdb7-23ebf99f5b76';
const item: InvoiceItem = {amount: 10, itemType: "TAX",description:"a tax item"};
const items = [item];

const response: AxiosResponse<killbill.InvoiceItem, any> = await api.createTaxItems(items, accountId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$item = new InvoiceItem();
$item -> setAmount(100);
$item -> setItemType("TAX");
$item -> setDescription("tax item");
$body = array($item);

$accountId = "f547bda2-ad09-4e79-84c3-9759939496dd";
$requestedDate = new \DateTime("2023-09-21");
$autoCommit = false;
$pluginProperty = array("pluginProperty_example");

$result = $apiInstance->createTaxItems($body, $xKillbillCreatedBy, $accountId, $xKillbillReason, $xKillbillComment, $autoCommit, $requestedDate, $pluginProperty);

Example Response:

[
  {
    "invoiceItemId": "e91e8d48-d8de-4931-9758-6cfff86cb2f4",
    "invoiceId": "434dd357-099d-45f8-9b48-79dcd20c61ce",
    "linkedInvoiceItemId": null,
    "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d",
    "childAccountId": null,
    "bundleId": null,
    "subscriptionId": null,
    "productName": null,
    "planName": null,
    "phaseName": null,
    "usageName": null,
    "prettyProductName": null,
    "prettyPlanName": null,
    "prettyPhaseName": null,
    "prettyUsageName": null,
    "itemType": "TAX",
    "description": "Tax",
    "startDate": "2018-07-20",
    "endDate": null,
    "amount": 50,
    "rate": null,
    "currency": "USD",
    "quantity": null,
    "itemDetails": null,
    "catalogEffectiveDate":null,
    "childItems": null,
    "auditLogs": []
  }
]

Request Body

A List of invoice item resource objects with at least the amount attribute populated. If multiple invoice items are specified, a single invoice is created with all the invoice items.

Query Parameters

Name Type Required Default Description
requestedDate string no current date requested date
autoCommit boolean no false If true, the resulting invoice should be COMMITTED.
pluginProperty array of strings no omit list of plugin properties, if any. Should be in the format key%3Dvalue

Response

If successful, returns a status code of 201 and an invoice item object.

Retrieve an invoice by id

Retrieves an invoice based on the invoiceId.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}

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/invoices/903e55d3-8072-47f1-80fc-32857dbdbcc5"    
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("922a83f4-ae08-4732-9dd9-35e13c332393");
Boolean withChildrenItems = true; //  Will include children items

Invoice invoiceWithItems = invoiceApi.getInvoice(invoiceId, 
                                                 withChildrenItems, 
                                                 AuditLevel.NONE, 
                                                 requestOptions);
invoice_id = "5c6083c1-a673-4b67-9b86-74139df50448"
with_children_items = false
audit = 'NONE'

invoice = KillBillClient::Model::Invoice.find_by_id(invoice_id,
                                          with_children_items,
                                          audit,
                                          options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = '4b16ad29-2f32-4e7e-85f9-99beda4ae7dd'

invoice = invoiceApi.get_invoice(invoice_id)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = 'fd9df8b8-f845-43a1-8fe8-73a8269c5bcc';

const response: AxiosResponse<killbill.Invoice, any> = await api.getInvoice(invoiceId);
$apiInstance = $client->getInvoiceApi();

$invoiceId = "0fd7d64a-90d2-4d4d-9123-e9c5c7f36a47";
$withChildrenItems = false;
$audit = "NONE";

$result = $apiInstance->getInvoice($invoiceId, $withChildrenItems, $audit);

Example Response:

{
  "amount": 50,
  "currency": "USD",
  "status": "COMMITTED",
  "creditAdj": 0,
  "refundAdj": 0,
  "invoiceId": "4bc38bfd-3210-4293-bcfc-7c95b2d1472a",
  "invoiceDate": "2023-09-18",
  "targetDate": "2023-09-18",
  "invoiceNumber": "6894",
  "balance": 50,
  "accountId": "d7ec4174-ab07-4e25-a917-ad020b755917",
  "bundleKeys": null,
  "credits": null,
  "items": [
    {
      "invoiceItemId": "af65fae9-1dd9-4340-87cb-8d2e9d7ed3d8",
      "invoiceId": "4bc38bfd-3210-4293-bcfc-7c95b2d1472a",
      "linkedInvoiceItemId": null,
      "accountId": "d7ec4174-ab07-4e25-a917-ad020b755917",
      "childAccountId": null,
      "bundleId": null,
      "subscriptionId": null,
      "productName": null,
      "planName": null,
      "phaseName": null,
      "usageName": null,
      "prettyProductName": null,
      "prettyPlanName": null,
      "prettyPhaseName": null,
      "prettyUsageName": null,
      "itemType": "TAX",
      "description": "Tax",
      "startDate": "2023-09-18",
      "endDate": null,
      "amount": 50,
      "rate": null,
      "currency": "USD",
      "quantity": null,
      "itemDetails": null,
      "catalogEffectiveDate": null,
      "childItems": null,
      "auditLogs": []
    }
  ],
  "trackingIds": [],
  "isParentInvoice": false,
  "parentInvoiceId": null,
  "parentAccountId": null,
  "auditLogs": []
}

Query Parameters

Name Type Required Default Description
withChildrenItems boolean no false If true, include children items (applicable only in the hierarchical mode if the current invoice corresponds to a parent invoice and isPaymentDelegatedToParent=true).
audit string no "NONE" Level of audit information to return:"NONE", "MINIMAL" (only inserts), or "FULL"

Returns

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

Retrieve an invoice by number

Retrieves an invoice based on the invoiceNumber.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/byNumber/{invoiceNumber

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/invoices/byNumber/310"
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

Integer invoiceNumber = 1;
Boolean withChildrenItems = false; //  Will not include children items

Invoice invoiceByNumber = invoiceApi.getInvoiceByNumber(invoiceNumber, 
                                                        withChildrenItems, 
                                                        AuditLevel.FULL, 
                                                        requestOptions);
invoice_number = "7318"
with_children_items = false
audit = 'NONE'

invoice = KillBillClient::Model::Invoice.find_by_number(invoice_number,
                                              with_children_items,
                                              audit,
                                              options)
invoiceApi = killbill.api.InvoiceApi()

invoice_number = '7452'

invoice = invoiceApi.get_invoice_by_number(invoice_number)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceNumber = 7463;

const response: AxiosResponse<killbill.Invoice, any> = await api.getInvoiceByNumber(invoiceNumber);
$apiInstance = $client->getInvoiceApi();

$invoiceNumber = 7457;
$withChildrenItems = false;
$audit = "NONE";

$result = $apiInstance->getInvoiceByNumber($invoiceNumber, $withChildrenItems, $audit);

Example Response:

{
  "amount": 50,
  "currency": "USD",
  "status": "COMMITTED",
  "creditAdj": 0,
  "refundAdj": 0,
  "invoiceId": "4bc38bfd-3210-4293-bcfc-7c95b2d1472a",
  "invoiceDate": "2023-09-18",
  "targetDate": "2023-09-18",
  "invoiceNumber": "6894",
  "balance": 50,
  "accountId": "d7ec4174-ab07-4e25-a917-ad020b755917",
  "bundleKeys": null,
  "credits": null,
  "items": [
    {
      "invoiceItemId": "af65fae9-1dd9-4340-87cb-8d2e9d7ed3d8",
      "invoiceId": "4bc38bfd-3210-4293-bcfc-7c95b2d1472a",
      "linkedInvoiceItemId": null,
      "accountId": "d7ec4174-ab07-4e25-a917-ad020b755917",
      "childAccountId": null,
      "bundleId": null,
      "subscriptionId": null,
      "productName": null,
      "planName": null,
      "phaseName": null,
      "usageName": null,
      "prettyProductName": null,
      "prettyPlanName": null,
      "prettyPhaseName": null,
      "prettyUsageName": null,
      "itemType": "TAX",
      "description": "Tax",
      "startDate": "2023-09-18",
      "endDate": null,
      "amount": 50,
      "rate": null,
      "currency": "USD",
      "quantity": null,
      "itemDetails": null,
      "catalogEffectiveDate": null,
      "childItems": null,
      "auditLogs": []
    }
  ],
  "trackingIds": [],
  "isParentInvoice": false,
  "parentInvoiceId": null,
  "parentAccountId": null,
  "auditLogs": []
}

Query Parameters

Name Type Required Default Description
withChildrenItems boolean no false If true, include children items (applicable only in the hierarchical mode if the current invoice corresponds to a parent invoice and isPaymentDelegatedToParent=true).
audit string no "NONE" Level of audit information to return:"NONE", "MINIMAL" (only inserts), or "FULL"

Returns

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

Retrieve an invoice by invoice item id

Retrieves an invoice based on the invoiceItemId corresponding to an invoice item.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/byItemId/{itemId}

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/invoices/byItemId/3f0aa8f7-ca75-40cc-8c78-15a15cdbb977"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceItemId = UUID.fromString("111732ad-196d-423f-8ccd-de44109dc944");
Boolean withChildrenItems = false; //  Will not include children items

Invoice invoiceByItemId = invoiceApi.getInvoiceByItemId(invoiceItemId, 
                                                        withChildrenItems, 
                                                        AuditLevel.NONE, 
                                                        requestOptions);
invoice_item_id = "14b0de07-6634-4e56-9062-156ba8e6c06d"
with_children_items = false
audit = 'NONE'

invoice = KillBillClient::Model::Invoice.find_by_invoice_item_id(invoice_item_id,
                                                       with_children_items,
                                                       audit,
                                                       options)
invoiceApi = killbill.api.InvoiceApi()

invoice_item_id = '5cc1dce5-7f95-4d8e-987b-27ddd9e5b171'

invoice = invoiceApi.get_invoice_by_item_id(invoice_item_id,
                                            with_children_items=True)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceItemId = 'ed7e1b5d-ed43-41bf-99ca-85ff2c88462d';

const response: AxiosResponse<killbill.Invoice, any> = await api.getInvoiceByItemId(invoiceItemId);
$apiInstance = $client->getInvoiceApi();

$itemId = "b912e57d-897c-4018-9802-66a030fad55f";
$withChildrenItems = false;
$audit = "NONE";

$result = $apiInstance->getInvoiceByItemId($itemId, $withChildrenItems, $audit);

Example Response:

{
  "amount": 50,
  "currency": "USD",
  "status": "COMMITTED",
  "creditAdj": 0,
  "refundAdj": 0,
  "invoiceId": "4bc38bfd-3210-4293-bcfc-7c95b2d1472a",
  "invoiceDate": "2023-09-18",
  "targetDate": "2023-09-18",
  "invoiceNumber": "6894",
  "balance": 50,
  "accountId": "d7ec4174-ab07-4e25-a917-ad020b755917",
  "bundleKeys": null,
  "credits": null,
  "items": [
    {
      "invoiceItemId": "af65fae9-1dd9-4340-87cb-8d2e9d7ed3d8",
      "invoiceId": "4bc38bfd-3210-4293-bcfc-7c95b2d1472a",
      "linkedInvoiceItemId": null,
      "accountId": "d7ec4174-ab07-4e25-a917-ad020b755917",
      "childAccountId": null,
      "bundleId": null,
      "subscriptionId": null,
      "productName": null,
      "planName": null,
      "phaseName": null,
      "usageName": null,
      "prettyProductName": null,
      "prettyPlanName": null,
      "prettyPhaseName": null,
      "prettyUsageName": null,
      "itemType": "TAX",
      "description": "Tax",
      "startDate": "2023-09-18",
      "endDate": null,
      "amount": 50,
      "rate": null,
      "currency": "USD",
      "quantity": null,
      "itemDetails": null,
      "catalogEffectiveDate": null,
      "childItems": null,
      "auditLogs": []
    }
  ],
  "trackingIds": [],
  "isParentInvoice": false,
  "parentInvoiceId": null,
  "parentAccountId": null,
  "auditLogs": []
}

Query Parameters

Name Type Required Default Description
withChildrenItems boolean no false If true, include children items (applicable only in the hierarchical mode if the current invoice corresponds to a parent invoice and isPaymentDelegatedToParent=true).
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 an invoice resource object.

Render an invoice as HTML

This API formats an invoice as an HTML page, that can be displayed or printed for a customer.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/html

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: text/html" \
    "http://127.0.0.1:8080/1.0/kb/invoices/903e55d3-8072-47f1-80fc-32857dbdbcc5/html"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("59860a0d-c032-456d-a35e-3a48fe8579e5");

String htmlInvoice = invoiceApi.getInvoiceAsHTML(invoiceId, requestOptions);
invoice_id = "5c6083c1-a673-4b67-9b86-74139df50448"
invoiceHTML = KillBillClient::Model::Invoice.as_html(invoice_id, options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = '4b16ad29-2f32-4e7e-85f9-99beda4ae7dd'

invoiceHTML = invoiceApi.get_invoice_as_html(invoice_id)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = 'fd9df8b8-f845-43a1-8fe8-73a8269c5bcc';

const response: AxiosResponse = await api.getInvoiceAsHTML(invoiceId);
$apiInstance = $client->getInvoiceApi();

$invoiceId = "0fd7d64a-90d2-4d4d-9123-e9c5c7f36a47";

$result = $apiInstance->getInvoiceAsHTML($invoiceId);

Example Response:

<html>
    <head>
        <style type="text/css">
            th {align=left; width=225px; border-bottom: solid 2px black;}
        </style>
    </head>
    <body>
        <h1>invoiceTitle</h1>
        <table>
            <tr>
                <td rowspan=3 width=350px>Insert image here</td>
                <td width=100px/>
                <td width=225px/>
                <td width=225px/>
            </tr>
            <tr>
                <td />
                <td align=right>invoiceDate</td>
                <td>Jul 20, 2018</td>
            </tr>
            <tr>
                <td />
                <td align=right>invoiceNumber</td>
                <td>310</td>
            </tr>
            <tr>
                <td>companyName</td>
                <td></td>
                <td align=right>accountOwnerName</td>
                <td>Another Name</td>
            </tr>
            <tr>
                <td>companyAddress</td>
                <td />
                <td />
                <td>john@127.0.0.1:8080</td>
            </tr>
            <tr>
                <td>companyCityProvincePostalCode</td>
                <td />
                <td />
                <td></td>
            </tr>
            <tr>
                <td>companyCountry</td>
                <td />
                <td />
                <td />
            </tr>
            <tr>
                <td><companyUrl</td>
                <td />
                <td />
                <td />
            </tr>
        </table>
        <br />
        <br />
        <br />
        <table>
            <tr>
                <th>invoiceItemBundleName</td>
                <th>invoiceItemDescription</td>
                <th>invoiceItemServicePeriod</td>
                <th>invoiceItemAmount</td>
            </tr>

            <tr>
                <td>Adjustment (account credit)</td>
                <td></td>
                <td>Jul 20, 2018 - Jul 20, 2018</td>
                <td>USD 50.00</td>
            </tr>

            <tr>
                <td>example</td>
                <td></td>
                <td>Jul 20, 2018 - Jul 20, 2018</td>
                <td>USD -50.00</td>
            </tr>

            <tr>
                <td colspan=4 />
            </tr>
            <tr>
                <td colspan=2 />
                <td align=right><strong>invoiceAmount</strong></td>
                <td align=right><strong>0.00</strong></td>
            </tr>
            <tr>
                <td colspan=2 />
                <td align=right><strong>invoiceAmountPaid</strong></td>
                <td align=right><strong>0.00</strong></td>
            </tr>
            <tr>
                <td colspan=2 />
                <td align=right><strong>invoiceBalance</strong></td>
                <td align=right><strong>0</strong></td>
            </tr>
        </table>
    </body>
</html>

Query Parameters

None.

Response

If successful, returns a status code of 200 and an HTML string corresponding to the invoice.

Change invoice status from DRAFT to COMMITTED

Commit a DRAFT invoice by changing its status to COMMITTED. The invoice becomes immutable and its balance is now included in account totals.

HTTP Request

PUT http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/commitInvoice

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 "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/invoices/903e55d3-8072-47f1-80fc-32857dbdbcc5/commitInvoice"  
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("ca09d09a-59b2-4ada-8c15-597c9efde46c");

invoiceApi.commitInvoice(invoiceId, requestOptions);
user = "demo"
reason = nil
comment = nil

invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = "2c98cfa2-7929-4cc2-9397-1624fb72c6d5"

invoice.commit(user, 
               reason, 
               comment, 
               options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = '18d23ef1-ea82-442d-8602-43305232f3e5'

invoiceApi.commit_invoice(invoice_id,
                          created_by='demo',
                          reason='reason',
                          comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = '926ff247-e220-4cf9-8829-c13e943e3809';

api.commitInvoice(invoiceId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "80bd3bf3-307f-438b-bf7a-7dc5e8addf19";

$apiInstance->commitInvoice($invoiceId, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment);

Query Parameters

None.

Response

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

Void an invoice

Change the status of an invoice to VOID. A void invoice is ignored by the rest of the system. There are some restrictions for this operation:

HTTP Request

PUT http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/voidInvoice

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 "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/invoices/18e9b3d9-9083-4725-9e8a-27d3a57c2e88/voidInvoice"    
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("e659f0f3-745c-46d5-953c-28fe9282fc7d");

invoiceApi.voidInvoice(invoiceId, requestOptions);
user = "demo"
reason = nil
comment = nil

invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = "6b877adc-0916-4409-ba95-f4e955772ea6"

invoice.void(user,
               reason,
               comment,
               options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = '18d23ef1-ea82-442d-8602-43305232f3e5'

invoiceApi.void_invoice(invoice_id,
                        created_by='demo',
                        reason='reason',
                        comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = '926ff247-e220-4cf9-8829-c13e943e3809';

api.voidInvoice(invoiceId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "80bd3bf3-307f-438b-bf7a-7dc5e8addf19";

$apiInstance->voidInvoice($invoiceId, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment);

Query Parameters

None.

Response

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

Adjust an invoice item

Adjust the amount for an invoice item. The system adds a new invoice item of type ITEM_ADJ to the invoice. If the invoice was already paid for, the system also adds another invoice item of type CBA_ADJ to adjust the credit amount in the next invoice. See Invoice Examples for more information.

Notes: The linkedInvoiceItemId field of the new invoice item points to the id of the invoice item being adjusted.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '{ "invoiceItemId": "903e55d3-8072-47f1-80fc-32857dbdbcc5", "invoiceId": "903e55d3-8072-47f1-80fc-32857dbdbcc5", "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d", "description": "Free adjustment: good customer", "amount": 50, "currency": "USD"}' \
    "http://127.0.0.1:8080/1.0/kb/invoices/903e55d3-8072-47f1-80fc-32857dbdbcc5"    
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID accountId = UUID.fromString("53805dbc-720a-4eaf-9072-ade723ee860f");
UUID invoiceId = UUID.fromString("4be08988-35a1-4fce-bebc-699af2a95b18");
UUID invoiceItemId = UUID.fromString("5f1e9142-b4de-4409-9366-9920cc1683e9");
BigDecimal adjustedAmount = BigDecimal.TEN;

InvoiceItem adjustmentInvoiceItem = new InvoiceItem();
adjustmentInvoiceItem.setAccountId(accountId);
adjustmentInvoiceItem.setInvoiceId(invoiceItemId);
adjustmentInvoiceItem.setInvoiceItemId(invoiceItemId);
adjustmentInvoiceItem.setAmount(adjustedAmount);
adjustmentInvoiceItem.setCurrency(Currency.USD);

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

Invoice result = invoiceApi.adjustInvoiceItem(invoiceId, 
                                              adjustmentInvoiceItem, 
                                              requestedDate,
                                              pluginProperty,
                                              requestOptions);
user = "demo"
reason = nil
comment = nil

invoice_item                 = KillBillClient::Model::InvoiceItem.new
invoice_item.account_id      = "3ee3aa82-1d45-4bbc-b36b-74d628e095d0"
invoice_item.invoice_id      = "2c98cfa2-7929-4cc2-9397-1624fb72c6d5"
invoice_item.invoice_item_id = "b311f709-ad51-4f67-8722-18ce04334c31"
invoice_item.amount          = 100.00
invoice_item.currency        = 'USD'
invoice_item.description     = 'Free adjustment: good customer'

invoice_item.update(user, 
                    reason, 
                    comment, 
                    options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = '4b16ad29-2f32-4e7e-85f9-99beda4ae7dd'
body = InvoiceItem(account_id='bdbed417-a84b-4303-958c-b88a36807416',
                   invoice_id='4b16ad29-2f32-4e7e-85f9-99beda4ae7dd',
                   invoice_item_id='5cc1dce5-7f95-4d8e-987b-27ddd9e5b171',
                   amount=10,
                   currency='USD',
                   description='Free adjustment: good customer')

invoiceApi.adjust_invoice_item(invoice_id,
                               body,
                               created_by='demo',
                               reason='reason',
                               comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const item: InvoiceItem = {accountId: "b462d167-d9bc-459a-bdb7-23ebf99f5b76", invoiceId: "4f948961-90a9-427b-bfbf-7583bee86711",invoiceItemId:"3fd23760-11be-447d-8c91-9a22037ca239", amount:10, description: "free adjustment, good customer"};
const invoiceId = '4f948961-90a9-427b-bfbf-7583bee86711';

api.adjustInvoiceItem(item, invoiceId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "b7c4ce68-e885-4f8b-8ee3-2eee7b3d8fb7";
$requestedDate = NULL;
$pluginProperty = array("pluginProperty_example");

$body = new InvoiceItem();
$body -> setAmount(20);
$body -> setAccountId("f547bda2-ad09-4e79-84c3-9759939496dd");
$body -> setInvoiceId($invoiceId);
$body -> setInvoiceItemId("00450fb0-25c2-4ad4-ac81-8d3258ec6b25");
$body -> setDescription("good customer - free adjustment");

$result = $apiInstance->adjustInvoiceItem($body, $xKillbillCreatedBy, $invoiceId, $xKillbillReason, $xKillbillComment, $requestedDate, $pluginProperty);

Request Body

An invoice item resource object with at least accountId, invoiceItemId, invoiceId, and amount attributes.

Query Parameters

Name Type Required Default Description
requestedDate string no current date requested date
pluginProperty array of strings no omit list of plugin properties, if any. Should be in the format key%3Dvalue

Returns

If successful, returns a status code of 201 and an empty body. In addition, a Location header containing the invoice id is returned.

Delete a CBA item

Delete a Credit Balance Adjust (CBA_ADJ) invoice item. There are some limitations and side effects with this api:

Deleting a positive CBA_ADJ (credit generation), may lead the system to reclaim portion of the used credit, possibly leaving some invoices with a balance.

Given an invoice, I1, where user added some credit ($12), we would see the following items: {CREDIT_ADJ: -12, CBA_ADJ: +12}. Given another invoice, I2, where the system invoiced for a recurring subscription, and where some of this credit was consumed, we would see the following items: {RECURRING: +10, CBA_ADJ: -10}. Deleting the CBA_ADJ from I1, would lead to the following resulting invoices: I1 {CREDIT_ADJ: 0, CBA_ADJ: 0} and I2 {RECURRING: +10, CBA_ADJ: 0}. The system zeroed-out the credit generation and the part that was used, and as a result I2 would be left with a balance of +10.

Deleting a negative CBA_ADJ would also leave invoice with a balance.

So deleting the CBA_ADJ from I2 in the example above would lead to the following invoice: I2 {RECURRING: +10, CBA_ADJ: 0} .

Attempting to delete system generated credit would fail.

In an in-advanced scenario where the system first invoiced for a recurring subscription ($20), and then repaired ($-8) for instance as a result of an early cancelation, we would have the following invoices: I1 {RECURRING: +20} and I2 {REPAIR_ADJ: -8, CBA_ADJ: +8}. Attempting to delete the CBA_ADJ on I2 would fail as the generation of credit was system generated, i.e. it happened as a result of a subscription change.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/{invoiceItemId}/cba

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/invoices/404a98a8-4dd8-4737-a39f-be871e916a8c/a35fb7b5-aec8-489e-aadf-c86107aa1d92/cba?accountId=8785164f-b5d7-4da1-9495-33f5105e8d80"    
UUID invoiceId = UUID.fromString("c0c2d79d-8b2e-4830-a05b-b9a43b38482c");
UUID invoiceItemId = UUID.fromString("29a8933a-2e5c-409c-97be-7a5964dbf708");
UUID accountId = UUID.fromString("41e61312-cfb1-4300-afc7-64bc5cb29e85");
invoiceApi.deleteCBA(invoiceId, invoiceItemId, accountId, requestOptions);
user = "demo"
reason = nil
comment = nil

invoice_item                 = KillBillClient::Model::InvoiceItem.new
invoice_item.account_id      = "3ee3aa82-1d45-4bbc-b36b-74d628e095d0"
invoice_item.invoice_id      = "2c98cfa2-7929-4cc2-9397-1624fb72c6d5"
invoice_item.invoice_item_id = "b311f709-ad51-4f67-8722-18ce04334c31"

invoice_item.delete(user, 
                    reason, 
                    comment, 
                    options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id='a493320b-29ab-4228-ad84-58d53e88b73b'
invoice_item_id='b3aeb9d7-4501-4285-8071-f5c02f45a659'
account_id = 'bdbed417-a84b-4303-958c-b88a36807416'

invoiceApi.delete_cba(invoice_id,
                      invoice_item_id,
                      account_id,
                      created_by='demo',
                      reason='reason',
                      comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const accountId = 'b462d167-d9bc-459a-bdb7-23ebf99f5b76';
const invoiceId = 'd723f109-7c4d-470e-9267-995610b02b28';
const invoiceItemId = '7b8d4e3e-0fa0-43fc-bac2-4a0147e9a185';

api.deleteCBA(invoiceId, invoiceItemId, accountId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "dff3b38a-4fcd-43f7-8fe9-7dcae2bc8269";
$invoiceItemId = "177cba3a-6775-4357-94cc-0f1e51136649";
$accountId = "f547bda2-ad09-4e79-84c3-9759939496dd";

$apiInstance->deleteCBA($invoiceId, $invoiceItemId, $accountId, $xKillbillCreatedBy, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
accountId string yes none account id

Response

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

Dry-run

In some situations, it is necessary to preview what a given customer will be invoiced for before making changes, or to verify what the system will generate at a future date. Kill Bill provides a dry-run invoice API to accomplish these goals. This API can be used to answer several distinct questions:

A dry run is based on a dry run resource object.

Generate a dry run invoice

This endpoint creates a dry-run invoice. Based on its parameters you can obtain answers to the different questions listed above.

Note: This endpoint is rather expensive, as it creates a full invoice run for the designated account, but no invoice will be created or persisted in the system.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/dryRun

Example Request:

# For targetDate
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '{ "dryRunType": "TARGET_DATE"}' \
    "http://localhost:8080/1.0/kb/invoices/dryRun?accountId=60a47168-7d36-4380-8ec7-e48cfe4e65d6&targetDate=2022-02-28"   

OR 

# upcoming invoice
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '{ "dryRunType": "UPCOMING_INVOICE"}' \
    "http://localhost:8080/1.0/kb/invoices/dryRun?accountId=2ad52f53-85ae-408a-9879-32a7e59dd03d"   

OR 

# START_BILLING
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '{ "dryRunType": "SUBSCRIPTION_ACTION","dryRunAction":"START_BILLING","planName":"pistol-monthly-notrial"}' \
    "http://localhost:8080/1.0/kb/invoices/dryRun?accountId=b462d167-d9bc-459a-bdb7-23ebf99f5b76"  

OR

# CHANGE
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '{ "dryRunType": "SUBSCRIPTION_ACTION","dryRunAction":"CHANGE","productName":"Standard", "productCategory":"BASE","billingPeriod":"MONTHLY","subscriptionId":"0b9efead-d5e4-40a9-8178-2286dee0fe48","bundleId":" 6ebcc573-c2c4-408a-b5c3-d6ae0dbae233"}' \
    "http://localhost:8080/1.0/kb/invoices/dryRun?accountId=60a47168-7d36-4380-8ec7-e48cfe4e65d6"  

OR

# STOP_BILLING
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '{ "dryRunType": "SUBSCRIPTION_ACTION","dryRunAction":"STOP_BILLING","subscriptionId":"0b9efead-d5e4-40a9-8178-2286dee0fe48","bundleId":"    6ebcc573-c2c4-408a-b5c3-d6ae0dbae233","effectiveDate":"2022-02-10"}' \
    "http://localhost:8080/1.0/kb/invoices/dryRun?accountId=60a47168-7d36-4380-8ec7-e48cfe4e65d6"            
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

DryRunType dryRunType = DryRunType.SUBSCRIPTION_ACTION;
SubscriptionEventType dryRunAction = SubscriptionEventType.START_BILLING;
PhaseType phaseType = null;
String productName = "Assault-Rifle";
ProductCategory productCategory = ProductCategory.BASE;
BillingPeriod billingPeriod = BillingPeriod.ANNUAL;
String priceListName = null;
UUID subscriptionId = null;
UUID bundleId = null;
LocalDate effectiveDate = null;
BillingActionPolicy billingPolicy = null;
List<PhasePrice> priceOverrides = null;
String planName = null;

Map<String, String> NULL_PLUGIN_PROPERTIES = null;

InvoiceDryRun dryRunArg = new InvoiceDryRun(dryRunType, 
        dryRunAction,
        phaseType,
        productName,
        productCategory,
        billingPeriod,
        priceListName,
        subscriptionId,
        bundleId,
        effectiveDate,
        billingPolicy,
        priceOverrides,
        planName);


UUID accountId = UUID.fromString("8452df66-ded8-4fba-b7dc-50302d19bc5b");
LocalDate targetDate = new LocalDate("2023-10-22");

Invoice dryRunInvoice = invoiceApi.generateDryRunInvoice(dryRunArg,
        accountId,
        targetDate,
        NULL_PLUGIN_PROPERTIES,
        requestOptions);
#
# This case is when you create a dry-run invoice with UPCOMING_INVOICE, 
# to see what is the next invoice that the system will generate for this account 
# 
account_id = "5527abbc-d83d-447f-bf3d-ab9542ea631e"
user = nil
reason = nil
comment = nil
target_date = nil
upcoming_invoice_target_date = true
plugin_properties = ["key%3Dvalue"]

KillBillClient::Model::Invoice.trigger_invoice_dry_run(account_id, 
                                                       target_date, 
                                                       upcoming_invoice_target_date,
                                                       plugin_properties,
                                                       user,
                                                       reason,
                                                       comment,
                                                       options)
#
# This case is when you create a dry-run invoice with UPCOMING_INVOICE, 
# to see what is the next invoice that the system will generate for this account 
# 
invoiceApi = killbill.api.InvoiceApi()

body = InvoiceDryRun(dry_run_type='UPCOMING_INVOICE')
account_id = '00e87495-92dc-4640-8490-e2c794748151'

invoice = invoiceApi.generate_dry_run_invoice(body,
                                              account_id,
                                              created_by='demo',
                                              reason='reason',
                                              comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const accountId = 'a24a1b9f-9d0f-4311-ad05-feac80f7b177';
const targetDate = '2023-10-26';
const invoiceDryRun: InvoiceDryRun = {dryRunType: "UPCOMING_INVOICE"};

const response: AxiosResponse = await api.generateDryRunInvoice(invoiceDryRun, accountId, 'created_by', targetDate);
$apiInstance = $client->getInvoiceApi();

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

$body = new InvoiceDryRun();
$body -> setDryRunType("UPCOMING_INVOICE");
$accountId = "a24a1b9f-9d0f-4311-ad05-feac80f7b177";
$targetDate = null;
$pluginProperty = array("pluginProperty_example");

$result = $apiInstance->generateDryRunInvoice($body, $xKillbillCreatedBy, $accountId, $xKillbillReason, $xKillbillComment, $targetDate, $pluginProperty);

Example Response:

{
  "amount": 60,
  "currency": "USD",
  "status": "COMMITTED",
  "creditAdj": 0,
  "refundAdj": 0,
  "invoiceId": "cf4d1d3b-81cf-4054-96d7-bbdada2b9bc2",
  "invoiceDate": "2022-01-31",
  "targetDate": "2022-02-28",
  "invoiceNumber": null,
  "balance": 60,
  "accountId": "60a47168-7d36-4380-8ec7-e48cfe4e65d6",
  "bundleKeys": null,
  "credits": null,
  "items": [
    {
      "invoiceItemId": "8c453b1b-ba2c-4c05-894f-e02eb2ee834e",
      "invoiceId": "cf4d1d3b-81cf-4054-96d7-bbdada2b9bc2",
      "linkedInvoiceItemId": null,
      "accountId": "60a47168-7d36-4380-8ec7-e48cfe4e65d6",
      "childAccountId": null,
      "bundleId": "6ebcc573-c2c4-408a-b5c3-d6ae0dbae233",
      "subscriptionId": "0b9efead-d5e4-40a9-8178-2286dee0fe48",
      "productName": "Standard",
      "planName": "standard-monthly",
      "phaseName": "standard-monthly-evergreen",
      "usageName": null,
      "prettyProductName": null,
      "prettyPlanName": null,
      "prettyPhaseName": null,
      "prettyUsageName": null,
      "itemType": "RECURRING",
      "description": "standard-monthly-evergreen",
      "startDate": "2022-02-28",
      "endDate": "2022-03-31",
      "amount": 30,
      "rate": 30,
      "currency": "USD",
      "quantity": null,
      "itemDetails": null,
      "catalogEffectiveDate": "2019-01-01T00:00:00.000Z",
      "childItems": null,
      "auditLogs": []
    },
    {
      "invoiceItemId": "c1e83a72-ef8e-42d4-93e1-b5f9390294b4",
      "invoiceId": "cf4d1d3b-81cf-4054-96d7-bbdada2b9bc2",
      "linkedInvoiceItemId": null,
      "accountId": "60a47168-7d36-4380-8ec7-e48cfe4e65d6",
      "childAccountId": null,
      "bundleId": "c22936f6-5105-45b6-b418-ebba142a17aa",
      "subscriptionId": "9cce25a5-6ef2-40fe-8718-ca22529fe9d8",
      "productName": "Standard",
      "planName": "standard-monthly",
      "phaseName": "standard-monthly-evergreen",
      "usageName": null,
      "prettyProductName": null,
      "prettyPlanName": null,
      "prettyPhaseName": null,
      "prettyUsageName": null,
      "itemType": "RECURRING",
      "description": "standard-monthly-evergreen",
      "startDate": "2022-02-28",
      "endDate": "2022-03-31",
      "amount": 30,
      "rate": 30,
      "currency": "USD",
      "quantity": null,
      "itemDetails": null,
      "catalogEffectiveDate": "2019-01-01T00:00:00.000Z",
      "childItems": null,
      "auditLogs": []
    }
  ],
  "trackingIds": [],
  "isParentInvoice": false,
  "parentInvoiceId": null,
  "parentAccountId": null,
  "auditLogs": []
}

Request Body

A dry run resource object. The dryRunType and sometimes dryRunAction must be specified. Other attributes depend on these:

dryRunType dryRunAction Other Required Attributes Other Optional Attributes Description
TARGET_DATE N/A none none Preview the invoice as of the target date specified as a query parameter
UPCOMING_INVOICE N/A none subscriptionId or bundleId (When specified, computes the upcoming invoice for the specified subscription/bundle. Note that if there are other subscriptions invoiced on the same day, these will also be included in the upcoming invoice) Preview the next scheduled invoice. targetDate query parameter does not need to be specified, it is ignored even if specified
SUBSCRIPTION_ACTION START_BILLING Either a combination of productName, productCategory, billingPeriod or planName. If the dry run is being generated for an ADDON product, then the bundleId also needs to be specified effectiveDate, priceListName, billingPolicy Preview the invoice that would be generated if the START_BILLING action is taken
SUBSCRIPTION_ACTION CHANGE subscriptionId, bundleId and either a combination of productName, productCategory, billingPeriod or planName effectiveDate, priceListName, billingPolicy Preview the invoice that would be generated if the CHANGE action is taken
SUBSCRIPTION_ACTION STOP_BILLING subscriptionId, bundleId, effectiveDate - Preview the invoice that would be generated if the STOP_BILLING action is taken

Query Parameters

Name Type Required Default Description
accountId string yes none Account id
targetDate string No current date Target date is the invoicing target date
pluginProperty array of strings no omit list of plugin properties, if any. Should be in the format key%3Dvalue

Note that for SUBSCRIPTION_ACTION, there are 2 dates to take into account:

Response

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

Invoice Groups

An invoice group is a group of invoices. An invoice group plugin can be used to split an invoice into multiple invoices. Such split invoices belong to a single invoice group.

Note that Kill Bill does not provide any reference implementation for an invoice group plugin. So anyone wishing to use this feature would need to create an invoice plugin and implement the InvoicePluginApi#getInvoiceGrouping method. We provide a demo plugin that demonstrates how an invoice group plugin can be implemented. When such a plugin is configured, an invoice group run would result in the generation of multiple invoices.

Trigger an invoice group run

Triggers an invoice group run for the associated account. This would result in the creation of split invoices only if an invoice group plugin is configured. Otherwise, this endpoint behaves the same way as the Trigger an invoice run endpoint.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/group

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/invoices/group?accountId=46897a8b-4ae8-45e2-b934-c4d00dba40a6" 
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID accountId = UUID.fromString("34a65013-2dd1-480e-b4b8-7999bb15ebce");
LocalDate targetDate = LocalDate.parse("2023-06-15");
Map<String, String> NULL_PLUGIN_PROPERTIES = null;

Invoices invoices = invoiceApi.createFutureInvoiceGroup(accountId, targetDate, NULL_PLUGIN_PROPERTIES, requestOptions);
user = "demo"
reason = nil
comment = nil

account_id = "3ee3aa82-1d45-4bbc-b36b-74d628e095d0"
target_date = "2024-12-05"
plugin_property = nil

KillBillClient::Model::Invoice.trigger_invoice_group_run(account_id,
                                                         target_date,
                                                         plugin_property
                                                         user,
                                                         reason,
                                                         comment,
                                                         options)

invoiceApi = killbill.api.InvoiceApi()

account_id = '8452df66-ded8-4fba-b7dc-50302d19bc5b'
target_date = datetime.date(2023, 11, 22)

invoiceApi.create_future_invoice_group(account_id,
                                       target_date=target_date,
                                       created_by='demo',
                                       reason='reason',
                                       comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const accountId = '8452df66-ded8-4fba-b7dc-50302d19bc5b';
const targetDate = '2024-02-22';

api.createFutureInvoiceGroup(accountId, 'created_by', targetDate);
$apiInstance = $client->getInvoiceApi();

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

$accountId = "8452df66-ded8-4fba-b7dc-50302d19bc5b";
$targetDate = new DateTime("2024-04-22");
$pluginProperty = array("pluginProperty_example");

$result = $apiInstance->createFutureInvoiceGroup($accountId, $xKillbillCreatedBy, $targetDate, $pluginProperty, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
accountId string yes none account id
targetDate string no current date target date (date up to which the account should be invoiced)
pluginProperty array of strings no omit list of plugin properties, if any. Should be in the format key%3Dvalue

Response

If successful, returns a status code of 201 and an empty body. A location header containing the UUID of the generated group (if any) is also included in the response. If there is nothing to invoice for, returns a 404 status code.

Retrieve an invoice group

Retrieves the invoices associated with the specified groupId.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/{groupId}/group

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/invoices/e7fc3529-92e1-4987-b5f1-08e558a36698/group?accountId=40630170-e390-4cc7-9381-3788a894ba04" 
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID accountId = UUID.fromString("62dfaf14-34c6-4756-8411-89c93b1cfba3");
UUID groupId = UUID.fromString("f5ecf703-10b9-4019-8044-8db1163bef56");

Invoices invoices = invoiceApi.getInvoicesGroup(groupId, accountId, requestOptions);
account_id = "3ee3aa82-1d45-4bbc-b36b-74d628e095d0"
group_id = "f5ecf703-10b9-4019-8044-8db1163bef56"
with_children_items = false
audit = "NONE"

KillBillClient::Model::Invoice.retrieve_invoice_group(account_id,
                                                      group_id,
                                                      with_children_items,
                                                      audit,
                                                      options)
invoiceApi = killbill.api.InvoiceApi()

account_id = '8452df66-ded8-4fba-b7dc-50302d19bc5b'
group_id = '51eae3dc-eec8-4ffa-b7d1-65b7b797538e'

invoice_group = invoiceApi.get_invoices_group(group_id, account_id)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const accountId = '8452df66-ded8-4fba-b7dc-50302d19bc5b';
const groupId = 'ad2921d2-a343-4115-9a51-32288f49e6f0';

const response: AxiosResponse<killbill.Invoice[], any> = await api.getInvoicesGroup(groupId, accountId);
$apiInstance = $client->getInvoiceApi();

$groupId = "ad2921d2-a343-4115-9a51-32288f49e6f0";
$accountId = "8452df66-ded8-4fba-b7dc-50302d19bc5b";
$withChildrenItems = false;
$audit = "NONE";

$result = $apiInstance->getInvoicesGroup($groupId, $accountId, $withChildrenItems, $audit);

Example Response:

[
  {
    "amount": 30,
    "currency": "USD",
    "status": "COMMITTED",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "f5ecf703-10b9-4019-8044-8db1163bef56",
    "invoiceDate": "2023-02-16",
    "targetDate": "2023-08-16",
    "invoiceNumber": "428",
    "balance": 30,
    "accountId": "62dfaf14-34c6-4756-8411-89c93b1cfba3",
    "bundleKeys": null,
    "credits": null,
    "items": [
      {
        "invoiceItemId": "faf4f9a3-943b-42c4-9705-1365cfd91cc7",
        "invoiceId": "f5ecf703-10b9-4019-8044-8db1163bef56",
        "linkedInvoiceItemId": null,
        "accountId": "62dfaf14-34c6-4756-8411-89c93b1cfba3",
        "childAccountId": null,
        "bundleId": "30a3a9bf-3fc7-4334-ac2e-064cdd99c9dc",
        "subscriptionId": "5c463a1a-e884-4177-aa2c-cb09aa45e39b",
        "productName": "Standard",
        "planName": "standard-monthly",
        "phaseName": "standard-monthly-evergreen",
        "usageName": null,
        "prettyProductName": "Standard",
        "prettyPlanName": "standard-monthly",
        "prettyPhaseName": "standard-monthly-evergreen",
        "prettyUsageName": null,
        "itemType": "RECURRING",
        "description": "standard-monthly-evergreen",
        "startDate": "2023-08-16",
        "endDate": "2023-09-16",
        "amount": 30,
        "rate": 30,
        "currency": "USD",
        "quantity": null,
        "itemDetails": null,
        "catalogEffectiveDate": "2020-01-01T00:00:00.000Z",
        "childItems": null,
        "auditLogs": []
      }
    ],
    "trackingIds": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  },
  {
    "amount": 30,
    "currency": "USD",
    "status": "COMMITTED",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "b2f575d9-9bb8-4b5a-8595-da001381fd13",
    "invoiceDate": "2023-02-16",
    "targetDate": "2023-08-16",
    "invoiceNumber": "429",
    "balance": 30,
    "accountId": "62dfaf14-34c6-4756-8411-89c93b1cfba3",
    "bundleKeys": null,
    "credits": null,
    "items": [
      {
        "invoiceItemId": "42376d22-4b19-4a79-816b-b4896f9e8f48",
        "invoiceId": "b2f575d9-9bb8-4b5a-8595-da001381fd13",
        "linkedInvoiceItemId": null,
        "accountId": "62dfaf14-34c6-4756-8411-89c93b1cfba3",
        "childAccountId": null,
        "bundleId": "c176641f-2b6e-4bcf-8264-bfa120bcb337",
        "subscriptionId": "d424e7d9-e81a-45c7-9e84-77316bfe0c80",
        "productName": "Standard",
        "planName": "standard-monthly",
        "phaseName": "standard-monthly-evergreen",
        "usageName": null,
        "prettyProductName": "Standard",
        "prettyPlanName": "standard-monthly",
        "prettyPhaseName": "standard-monthly-evergreen",
        "prettyUsageName": null,
        "itemType": "RECURRING",
        "description": "standard-monthly-evergreen",
        "startDate": "2023-08-16",
        "endDate": "2023-09-16",
        "amount": 30,
        "rate": 30,
        "currency": "USD",
        "quantity": null,
        "itemDetails": null,
        "catalogEffectiveDate": "2020-01-01T00:00:00.000Z",
        "childItems": null,
        "auditLogs": []
      }
    ],
    "trackingIds": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  }
]

Query Parameters

Name Type Required Default Description
accountId string yes none accountId
withChildrenItems boolean no false If true, include children items
audit string no "NONE" Level of audit information to return:"NONE", "MINIMAL" (only inserts), or "FULL"

Returns If successful, returns a status code of 200 and a list of invoice objects for this group.

Payments

These endpoints relate to payments on an invoice. More information can be found at Invoice Payments.

Trigger a payment for an invoice

This API causes the system to generate a payment for an invoice.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/payments

Example Request:

curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '{ "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d", "purchasedAmount": 50, "targetInvoiceId": "903e55d3-8072-47f1-80fc-32857dbdbcc5"}' \
    "http://localhost:8080/1.0/kb/invoices/903e55d3-8072-47f1-80fc-32857dbdbcc5/payments"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("4defec0a-3ecb-4d6f-9b97-c3842734d95f");
UUID accountId = UUID.fromString("14eadca7-dc35-4bbf-bb2b-fabad9bfebcf");

InvoicePayment invoicePayment = new InvoicePayment();
invoicePayment.setPurchasedAmount(BigDecimal.TEN);
invoicePayment.setAccountId(accountId);
invoicePayment.setTargetInvoiceId(invoiceId);

Boolean externalPayment = true; // Will use a external payment method
List<String> controlPluginNames = null;
Map<String, String> NULL_PLUGIN_PROPERTIES = null;
InvoicePayment result = invoiceApi.createInstantPayment(invoiceId, 
                                                        invoicePayment, 
                                                        externalPayment, 
                                                        controlPluginNames,
                                                        NULL_PLUGIN_PROPERTIES, 
                                                        requestOptions);
user = "demo"
reason = nil
comment = nil

payment = KillBillClient::Model::InvoicePayment.new
payment.account_id = "a24a1b9f-9d0f-4311-ad05-feac80f7b177"
payment.target_invoice_id = "bb9cf385-cc78-46a6-b069-924bdfdeb4f7"
payment.purchased_amount = '50.0'

external_payment = true

payment.create(external_payment,
               user,
               reason,
               comment,
               options)
invoiceApi = killbill.api.InvoiceApi()

account_id = '04779ade-11f9-48d1-88a1-a63be84d1cb7'
invoice_id = '46ab72dc-8abf-4984-818b-cf1558c7ef4b'

body = InvoicePayment(account_id=account_id,
                      purchased_amount=50.0,
                      target_invoice_id=invoice_id)

invoiceApi.create_instant_payment(invoice_id,
                                  body,
                                  external_payment=True,
                                  created_by='demo',
                                  reason='reason',
                                  comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const accountId = 'ceaa4c46-723e-4229-ba77-c8656572e8ea';
const invoiceId = '80825f6b-dc95-46f9-8e7e-ac16bf658f81';
const invoicePayment: InvoicePayment = {accountId: accountId, targetInvoiceId: invoiceId, purchasedAmount:100};

api.createInstantPayment(invoicePayment, invoiceId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "bb9cf385-cc78-46a6-b069-924bdfdeb4f7";
$accountId = "a24a1b9f-9d0f-4311-ad05-feac80f7b177";
$externalPayment = true;
$controlPluginName = array("controlPluginName_example");
$pluginProperty = array("pluginProperty_example");

$body = new InvoicePayment();
$body -> setAccountId($accountId);
$body -> setTargetInvoiceId($invoiceId);
$body -> setPurchasedAmount(100);

$result = $apiInstance->createInstantPayment($body, $xKillbillCreatedBy, $invoiceId, $xKillbillReason, $xKillbillComment, $externalPayment, $controlPluginName, $pluginProperty);

Request Body

An InvoicePayment resource object, with at least the following attributes: accountId, and purchasedAmount.

Query Parameters

Name Type Required Default Description
externalPayment boolean no false If true, the payment method should be defaulted to the (system provided) external payment method.
controlPluginName array of strings no omit list of payment control plugin names.
pluginProperty array of strings no omit list of plugin properties, if any. Should be in the format key%3Dvalue

Response

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

Retrieve payments associated with an invoice

Returns a list of Invoice Payment objects corresponding to payments associated with the invoice.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/payments

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/invoices/903e55d3-8072-47f1-80fc-32857dbdbcc5/payments"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("ca09d09a-59b2-4ada-8c15-597c9efde46c");
Boolean withPluginInfo = false; // Will not reflect plugin info
Boolean withAttempts = false; // Will not reflect payment attempts

InvoicePayments invoicePayments = invoiceApi.getPaymentsForInvoice(invoiceId,
        withPluginInfo,
        withAttempts,
        AuditLevel.NONE,
        requestOptions);
invoice_id = "3ee3aa82-1d45-4bbc-b36b-74d628e095d0"
with_plugin_info = false
with_attempts = false
audit = "NONE"

KillBillClient::Model::Invoice.retrieve_payments_for_invoice(invoice_id,
                                                      with_plugin_info,
                                                      with_attempts,
                                                      audit,
                                                      options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = '46ab72dc-8abf-4984-818b-cf1558c7ef4b'

invoice_payments = invoiceApi.get_payments_for_invoice(invoice_id)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = '80825f6b-dc95-46f9-8e7e-ac16bf658f81';

const response: AxiosResponse<killbill.InvoicePayment[], any> = await api.getPaymentsForInvoice(invoiceId);
$apiInstance = $client->getInvoiceApi();

$invoiceId = "bb9cf385-cc78-46a6-b069-924bdfdeb4f7";
$withPluginInfo = false;
$withAttempts = false;
$audit = "NONE";

$result = $apiInstance->getPaymentsForInvoice($invoiceId, $withPluginInfo, $withAttempts, $audit);

Example Response:

{
  "targetInvoiceId": "903e55d3-8072-47f1-80fc-32857dbdbcc5",
  "accountId": "8b66b9f9-bfb4-463a-86c7-e267128a294a",
  "paymentId": "cc7fcd4d-e701-4679-9741-41289103db83",
  "paymentNumber": "19",
  "paymentExternalKey": "cc7fcd4d-e701-4679-9741-41289103db83",
  "authAmount": 0,
  "capturedAmount": 0,
  "purchasedAmount": 500,
  "refundedAmount": 0,
  "creditedAmount": 0,
  "currency": "USD",
  "paymentMethodId": "39f3461c-5357-42f7-a8a9-ec79502fdb6b",
  "transactions": [
    {
      "transactionId": "6787dc2d-4f5e-49b5-9764-0070fd1238c2",
      "transactionExternalKey": "6787dc2d-4f5e-49b5-9764-0070fd1238c2",
      "paymentId": "cc7fcd4d-e701-4679-9741-41289103db83",
      "paymentExternalKey": "cc7fcd4d-e701-4679-9741-41289103db83",
      "transactionType": "PURCHASE",
      "amount": 500,
      "currency": "USD",
      "effectiveDate": "2018-07-19T20:48:34.000Z",
      "processedAmount": 500,
      "processedCurrency": "USD",
      "status": "SUCCESS",
      "gatewayErrorCode": null,
      "gatewayErrorMsg": null,
      "firstPaymentReferenceId": null,
      "secondPaymentReferenceId": null,
      "properties": null,
      "auditLogs": []
    }
  ],
  "paymentAttempts": null,
  "auditLogs": []
}

Query Parameters

Name Type Required Default Description
withPluginInfo boolean no false If true, plugin info is included
withAttempts boolean no false If true, payment attempts are included
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 List of InvoicePayment resource objects.

Custom Fields

Custom fields are {key, value} attributes that can be attached to any customer resource. In particular they can be added to invoices. For details on Custom Fields see Custom Field.

Add custom fields to an invoice

Adds one or more custom fields to an invoice object. Existing custom fields are not disturbed.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/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 "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '[ { "objectType": "INVOICE", "name": "Test Custom Field", "value": "demo_test_value" }]' \
    "http://127.0.0.1:8080/1.0/kb/invoices/2cd2f4b5-a1c0-42a7-924f-64c7b791332d/customFields"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("59860a0d-c032-456d-a35e-3a48fe8579e5");

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

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

invoiceApi.createInvoiceCustomFields(invoiceId, 
                                     customFields, 
                                     requestOptions);
user = "demo"
reason = nil
comment = nil

invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = '7bf0f3d6-4ffb-4d5a-98c7-1158083432d0'

custom_fields = []
custom_field = KillBillClient::Model::CustomFieldAttributes.new
custom_field.object_type = 'INVOICE'
custom_field.name = 'Test Custom Field'
custom_field.value = 'test_value'
custom_fields.push custom_field

invoice.add_custom_field(custom_fields,
                         user,
                         reason,
                         comment,
                         options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = 'b64bd7d2-167b-4e89-bb76-15ee955801f1'
body = CustomField(name='Test Custom Field', value='test_value')

invoiceApi.create_invoice_custom_fields(invoice_id,
                                        [body],
                                        created_by='demo',
                                        reason='reason',
                                        comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

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

const invoiceId = '800ca6d0-8c33-458c-bf1a-4de22e960441';

api.createInvoiceCustomFields(customFields, invoiceId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "800ca6d0-8c33-458c-bf1a-4de22e960441";

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

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

Request Body

A list of Custom Field objects. Each object should specify at least the name and value attribute. For example:

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

Query Parameters

None.

Response

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

Retrieve invoice custom fields

Retrieve the custom fields associated with an invoice

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/customFields

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/invoices/2cd2f4b5-a1c0-42a7-924f-64c7b791332d/customFields"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("59860a0d-c032-456d-a35e-3a48fe8579e5");

List<CustomField> customFields = invoiceApi.getInvoiceCustomFields(invoiceId,
                                                                   AuditLevel.NONE,
                                                                   requestOptions);
invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = '7bf0f3d6-4ffb-4d5a-98c7-1158083432d0'

audit = 'NONE'

custom_fields = invoice.custom_fields(audit, options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = 'b64bd7d2-167b-4e89-bb76-15ee955801f1'

custom_fields = invoiceApi.get_invoice_custom_fields(invoice_id)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = '800ca6d0-8c33-458c-bf1a-4de22e960441';
const audit = 'NONE';

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

$invoiceId = "800ca6d0-8c33-458c-bf1a-4de22e960441";
$audit = "NONE";

$result = $apiInstance->getInvoiceCustomFields($invoiceId, $audit);

Example Response:

[
  {
    "customFieldId": "349de10f-4bb1-4e1a-93f6-11b745200bf5",
    "objectId": "2cd2f4b5-a1c0-42a7-924f-64c7b791332d",
    "objectType": "INVOICE",
    "name": "Test Custom Field",
    "value": "demo_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 an invoice

Modify the custom fields associated with an invoice. 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/invoices/{invoiceId}/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 "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '[ { "customFieldId": "9e0c4b85-c257-437c-ae9c-d32eac6f010c", "objectId": "7bf0f3d6-4ffb-4d5a-98c7-1158083432d0", "value": "new value" }]' \
    "http://127.0.0.1:8080/1.0/kb/invoices/7bf0f3d6-4ffb-4d5a-98c7-1158083432d0/customFields"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("59860a0d-c032-456d-a35e-3a48fe8579e5");

UUID customFieldsId = UUID.fromString("9913e0f6-b5ef-498b-ac47-60e1626eba8f");

CustomField customFieldModified = new CustomField();
customFieldModified.setCustomFieldId(customFieldsId);
customFieldModified.setValue("NewValue");

CustomFields customFields = new CustomFields();
customFields.add(customFieldModified);

invoiceApi.modifyInvoiceCustomFields(invoiceId, 
                                     customFields, 
                                     requestOptions);
user = "demo"
reason = nil
comment = nil

invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = '7bf0f3d6-4ffb-4d5a-98c7-1158083432d0'

custom_fields = []
custom_field = KillBillClient::Model::CustomFieldAttributes.new
custom_field.custom_field_id = 'ec53d741-e52a-4860-a6d3-03bb22b24a90'
custom_field.value = 'new value'
custom_fields.push custom_field

invoice.modify_custom_field(custom_fields,
                            user,
                            reason,
                            comment,
                            options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = 'b64bd7d2-167b-4e89-bb76-15ee955801f1'
custom_field_id = 'da4c9071-e3da-418c-aa28-2b7cbf9ec3c8'
body = CustomField(custom_field_id=custom_field_id, value='New Value')

invoiceApi.modify_invoice_custom_fields(invoice_id,
                                        [body],
                                        created_by='demo',
                                        reason='reason',
                                        comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = '800ca6d0-8c33-458c-bf1a-4de22e960441';

const customField: CustomField = {customFieldId: "45ee24dd-cb1c-48a9-91a8-ecf5b76fd76b", value: "new_value"};
    const customFields = [customField];

api.modifyInvoiceCustomFields(customFields, invoiceId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "800ca6d0-8c33-458c-bf1a-4de22e960441";

$customField = new CustomField();
$customField -> setCustomFieldId('70749248-8bc5-4a98-9238-9eda7ed34d56');
$customField -> setValue('new_value');
$body = array($customField);

$apiInstance->modifyInvoiceCustomFields($body, $xKillbillCreatedBy, $invoiceId, $xKillbillReason, $xKillbillComment);

Requst Body

A list of Custom Field objects specifying the id and the new value for the custom fields to be modified. Each object should specify at least the customFieldId and value attribute. For example:

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

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

Query Parameters

None.

Response

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

Remove custom fields from invoice

Delete one or more custom fields from an invoice. 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 invoice.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/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" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    "http://127.0.0.1:8080/1.0/kb/invoices/2cd2f4b5-a1c0-42a7-924f-64c7b791332d/customFields?customField=349de10f-4bb1-4e1a-93f6-11b745200bf5"  
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("59860a0d-c032-456d-a35e-3a48fe8579e5");

UUID customFieldsId = UUID.fromString("9913e0f6-b5ef-498b-ac47-60e1626eba8f");
List<UUID> customFieldsList = List.of(customFieldsId);

invoiceApi.deleteInvoiceCustomFields(invoiceId, 
                                     customFieldsList, 
                                     requestOptions);
user = "demo"
reason = nil
comment = nil

invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = '7bf0f3d6-4ffb-4d5a-98c7-1158083432d0'

custom_field_ids = []
custom_field_id = 'ec53d741-e52a-4860-a6d3-03bb22b24a90'
custom_field_ids.push custom_field_id

invoice.remove_custom_field(custom_field_ids,
                            user,
                            reason,
                            comment,
                            options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = 'b64bd7d2-167b-4e89-bb76-15ee955801f1'
custom_fields = ['da4c9071-e3da-418c-aa28-2b7cbf9ec3c8']

invoiceApi.delete_invoice_custom_fields(invoice_id=invoice_id,
                                        custom_field=custom_fields,
                                        created_by='demo',
                                        reason='reason',
                                        comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = '800ca6d0-8c33-458c-bf1a-4de22e960441';

const customField = '45ee24dd-cb1c-48a9-91a8-ecf5b76fd76b';
const customFields = [customField];

api.deleteInvoiceCustomFields(invoiceId, 'created_by', customFields);
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "800ca6d0-8c33-458c-bf1a-4de22e960441";

$customFields = array("70749248-8bc5-4a98-9238-9eda7ed34d56");

$apiInstance->deleteInvoiceCustomFields($invoiceId, $xKillbillCreatedBy, $customFields, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
customField string yes 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 Tags for an introduction to tags.

The only system tag applicable for an Invoice is WRITTEN_OFF (00000000-0000-0000-0000-000000000004), which as it's name indicates, is used to write off an unpaid invoice, bringing its balance to $0.

Add tags to invoice

This API adds one or more tags to an invoice. The tag definition corresponding to the tag being added must already exist.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/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 "Accept: application/json" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '[ "00000000-0000-0000-0000-000000000004"]' \
    "http://127.0.0.1:8080/1.0/kb/invoices/2cd2f4b5-a1c0-42a7-924f-64c7b791332d/tags"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("45d6f4c5-21be-49b1-99c5-7b0c3c985bf0");

UUID writtenOffId = UUID.fromString("00000000-0000-0000-0000-000000000004");

Tags result = invoiceApi.createInvoiceTags(invoiceId, 
                                           List.of(writtenOffId), 
                                           requestOptions);
user = "demo"
reason = nil
comment = nil

invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = '7bf0f3d6-4ffb-4d5a-98c7-1158083432d0'

tag_definition_ids = ['2c1f8309-24d7-437c-971b-7e68ff2d393a']

invoice.add_tags_from_definition_ids(tag_definition_ids,
               user,
               reason,
               comment,
               options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = 'b64bd7d2-167b-4e89-bb76-15ee955801f1'
tagDefIds = ["00000000-0000-0000-0000-000000000004"]

invoiceApi.create_invoice_tags(invoice_id,
                               tagDefIds,
                               created_by='demo',
                               reason='reason',
                               comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = '800ca6d0-8c33-458c-bf1a-4de22e960441';
const tagDefIds = ['00000000-0000-0000-0000-000000000004'];

api.createInvoiceTags(tagDefIds, invoiceId, 'created_by');
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "800ca6d0-8c33-458c-bf1a-4de22e960441";
$tagDefIds = array("00000000-0000-0000-0000-000000000004");

$result = $apiInstance->createInvoiceTags($tagDefIds, $xKillbillCreatedBy, $invoiceId, $xKillbillReason, $xKillbillComment);

Request Body

A JSON array containing one or more tag definition ids to be added as tags.

Query Parameters

None.

Returns

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

Retrieve invoice tags

Retrieve all tags attached to this invoice.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/tags

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/invoices/2cd2f4b5-a1c0-42a7-924f-64c7b791332d/tags"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("e659f0f3-745c-46d5-953c-28fe9282fc7d");

Boolean includedDeleted = false; // Will not include deleted tags

List<Tag> tags = invoiceApi.getInvoiceTags(invoiceId, 
                                           includedDeleted, 
                                           AuditLevel.FULL, 
                                           requestOptions);
invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = '7bf0f3d6-4ffb-4d5a-98c7-1158083432d0'

included_deleted = false
audit = 'NONE'

tags = invoice.tags(included_deleted,
             audit,
             options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = 'b64bd7d2-167b-4e89-bb76-15ee955801f1'

tags = invoiceApi.get_invoice_tags(invoice_id)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = '800ca6d0-8c33-458c-bf1a-4de22e960441';
const includeDeleted = false;
const audit = 'NONE';

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

$invoiceId = "800ca6d0-8c33-458c-bf1a-4de22e960441";
$includedDeleted = false;
$audit = "NONE";

$result = $apiInstance->getInvoiceTags($invoiceId, $includedDeleted, $audit);

Example Response:

[
  {
    "tagId": "e054c84a-0518-4611-92a8-53e849f0affd",
    "objectType": "INVOICE",
    "objectId": "2cd2f4b5-a1c0-42a7-924f-64c7b791332d",
    "tagDefinitionId": "00000000-0000-0000-0000-000000000002",
    "tagDefinitionName": "AUTO_INVOICING_OFF",
    "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" (only inserts), or "FULL"

Response

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

Remove tags from invoice

This API deletes one or more tags attached to an invoice.

HTTP Request

DELETE http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/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" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    "http://127.0.0.1:8080/1.0/kb/invoices/2cd2f4b5-a1c0-42a7-924f-64c7b791332d/tags?tagDef=00000000-0000-0000-0000-000000000002"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("e659f0f3-745c-46d5-953c-28fe9282fc7d");
UUID autoPayOffId = UUID.fromString("00000000-0000-0000-0000-000000000001");

invoiceApi.deleteInvoiceTags(invoiceId, 
                             List.of(autoPayOffId), 
                             requestOptions);
user = "demo"
reason = nil
comment = nil

invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = '7bf0f3d6-4ffb-4d5a-98c7-1158083432d0'

tag_definition_ids = ['2c1f8309-24d7-437c-971b-7e68ff2d393a']

invoice.remove_tags_from_definition_ids(tag_definition_ids,
                  user,
                  reason,
                  comment,
                  options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = 'b64bd7d2-167b-4e89-bb76-15ee955801f1'
tagDefIds = ['00000000-0000-0000-0000-000000000004']

invoiceApi.delete_invoice_tags(invoice_id,
                               tag_def=tagDefIds,
                               created_by='demo',
                               reason='reason',
                               comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = '800ca6d0-8c33-458c-bf1a-4de22e960441';
const tagDefIds = ['00000000-0000-0000-0000-000000000004'];

api.deleteInvoiceTags(invoiceId, 'created_by', tagDefIds);
$apiInstance = $client->getInvoiceApi();

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

$invoiceId = "800ca6d0-8c33-458c-bf1a-4de22e960441";
$tagDef = array("00000000-0000-0000-0000-000000000004");

$apiInstance->deleteInvoiceTags($invoiceId, $xKillbillCreatedBy, $tagDef, $xKillbillReason, $xKillbillComment);

Query Parameters

Name Type Required Default Description
tagDef array of string yes 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.

Translation

These endpoints support translation of invoices to a different language when required by the customer. Translation replaces words and phrases in an invoice or catalog with the equivalent words or phrases in a different language. A tenant may upload translation tables for specific locales (e.g., locale fr_FR for French). When a customer accesses an invoice, that invoice is generated from the system data, formatted using the appropriate template, and translated according to the locale of the customer's account, if a translation table exists for that locale.

Refer to the Invoice templates document and Internationalization manual for an introduction to the translation process/Kill Bill's internationalization support.

Upload the catalog translation for the tenant

Uploads a catalog translation table that will be saved under a specified locale. The translation table provides a translation for specific names in the current catalog that may appear on an invoice (for example, plan names, product names, etc.).

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/catalogTranslation/{locale}

Example Request:

# specify the translations in the request body
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/plain" \
    -H "Accept: text/plain" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '"sports-monthly = Voiture Sport
silver-monthly = plan d'argent mensuel"' \
    "http://localhost:8080/1.0/kb/invoices/catalogTranslation/fr_FR"

OR 
# specify a properties file containing the translations
curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H 'X-Killbill-CreatedBy: admin' \
     -H "Content-Type: text/plain" \
     -X POST \
     -d @CatalogTranslation_de_DE.properties \
     http://127.0.0.1:8080/1.0/kb/invoices/catalogTranslation/de_DE
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

String locale = "en_US";
String body = "gold-monthly=plan";
Boolean deleteIfExists = true;
invoiceApi.uploadCatalogTranslation(locale, body, deleteIfExists,requestOptions);
user = "demo"
reason = nil
comment = nil

catalog_translation = 'sports-monthly = Voiture Sport'
locale = "fr_FR"
delete_if_exists = true

KillBillClient::Model::Invoice.upload_catalog_translation(catalog_translation,
                                                          locale,
                                                          delete_if_exists,
                                                          user,
                                                          reason,
                                                          comment,
                                                          options)
invoiceApi = killbill.api.InvoiceApi()

locale = 'fr_FR'
body = 'sports-monthly = Voiture Sport'

invoiceApi.upload_catalog_translation(locale,
                                      body,
                                      created_by='demo',
                                      reason='reason',
                                      comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const locale = 'fr_FR';
const deleteIfExists = true;
const body = 'sports-monthly = Voiture Sport';

api.uploadCatalogTranslation(body, locale, 'created_by', deleteIfExists);
$apiInstance = $client->getInvoiceApi();

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

$body = "sports-monthly = Voiture Sport";
$locale = "fr_FR";
$deleteIfExists = true;

$result = $apiInstance->uploadCatalogTranslation($body, $xKillbillCreatedBy, $locale, $xKillbillReason, $xKillbillComment, $deleteIfExists);

Request Body

A table of translation items. For example:

gold-monthly = plan Or mensuel silver-monthly = plan d'argent mensuel

Note that this table does not use a special syntax such as JSON. The equals sign is the only punctuation. There are no brackets or quotation marks.

Alternatively, the path of a properties file containing the translations can also be specified as the request body.

Query Parameters

Name Type Required Default Description
deleteIfExists boolean no false if true, delete any existing translations

Response

If successful, returns a status code of 201 and a Location header that can be used to retrieve the catalog translation for the locale.

Retrieve the catalog translation for the tenant

Retrieves the catalog translation table that was previously uploaded for a particular locale, if any.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/catalogTranslation/{locale}

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: text/plain" \
    "http://localhost:8080/1.0/kb/invoices/catalogTranslation/fr_FR"    
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

String locale = "en_US";
String translation = invoiceApi.getCatalogTranslation(locale, requestOptions);
locale = "fr_FR"
translations = KillBillClient::Model::Invoice.get_catalog_translation(locale, options)
invoiceApi = killbill.api.InvoiceApi()

locale = 'fr_FR'

translations = invoiceApi.get_catalog_translation(locale)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const locale = 'fr_FR';

const response: AxiosResponse = await api.getCatalogTranslation(locale);
$apiInstance = $client->getInvoiceApi();

$locale = "fr_FR";

$result = $apiInstance->getCatalogTranslation($locale);

Example Response:

{
    "sports-monthly = Voiture Sport"
}

Query Parameters

None.

Response

If successful, returns a status code of 200 and the translation table. A status code of 404 means no table was found for the specified locale.

Upload the invoice translation for the tenant

Uploads an invoice translation table that will be saved under a specified locale. The translation table provides a translation for specific names in the corresponding invoice template (for example invoice title, invoice date, etc.).

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/translation/{locale}

Example Request:

# specify the translations in the request body
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/plain" \
    -H "Accept: text/plain" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d "invoiceTitle=FACTURE
invoiceDate=Date:
invoiceNumber=Facture #" \
    "http://localhost:8080/1.0/kb/invoices/translation/fr_FR"

OR 

# specify a properties file containing the translations
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/plain" \
    -H "Accept: text/plain" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
     --data-binary @InvoiceTranslation_de_DE.properties \
    "http://localhost:8080/1.0/kb/invoices/translation/de_DE?deleteIfExists=true"
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

String locale = "en_US";
String body = "gold-monthly=plan";
Boolean deleteIfExists = true;
String translation = invoiceApi.uploadInvoiceTranslation(locale, body, deleteIfExists,requestOptions);
user = "demo"
reason = nil
comment = nil

invoice_translation = 'invoiceDate = date de facture'
locale = "fr_FR"
delete_if_exists = true
KillBillClient::Model::Invoice.upload_invoice_translation(invoice_translation,
                                                          locale,
                                                          delete_if_exists,
                                                          user,
                                                          reason,
                                                          comment,
                                                          options)
invoiceApi = killbill.api.InvoiceApi()

locale = 'fr_FR'
body = "invoiceDate = date de facture"
delete_if_exists = True

invoiceApi.upload_invoice_translation(locale,
                                      body,
                                      delete_if_exists=delete_if_exists,
                                      created_by='demo',
                                      reason='reason',
                                      comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const locale = 'fr_FR';
const deleteIfExists = true;
const body = 'invoiceDate = date de facture';

api.uploadInvoiceTranslation(body, locale, 'created_by', deleteIfExists);
$apiInstance = $client->getInvoiceApi();

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

$body = "invoiceDate = date de facture";
$locale = "fr_FR";
$deleteIfExists = true;

$result = $apiInstance->uploadInvoiceTranslation($body, $xKillbillCreatedBy, $locale, $xKillbillReason, $xKillbillComment, $deleteIfExists);

Request Body

A table of translation items. For example:

invoiceTitle=FACTURE invoiceDate=Date: invoiceNumber=Facture # invoiceAmount=Montant à payer

Note that this table does not use a special syntax such as JSON. The equals sign is the only punctuation. There are no brackets or quotation marks.

Alternatively, the path of a properties file containing the translations can also be specified as the request body.

Query Parameters

Name Type Required Default Description
deleteIfExists boolean no false delete translation if exists

Response

If successful, returns a status code of 201 and a Location header that can be used to retrieve the invoice translations for the locale.

Retrieve the invoice translation for the tenant

Retrieves the invoice translation table that was previously uploaded for a particular locale, if any.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/translation/{locale}

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: text/plain" \
    "http://localhost:8080/1.0/kb/invoices/translation/fr_FR"   
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

String locale = "en_US";
String translation = invoiceApi.getInvoiceTranslation(locale, requestOptions);

locale = "fr_FR"
translations = KillBillClient::Model::Invoice.get_invoice_translation(locale,options)
invoiceApi = killbill.api.InvoiceApi()

locale = 'fr_FR'

translations = invoiceApi.get_invoice_translation(locale)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const locale = 'fr_FR';

const response: AxiosResponse = await api.getInvoiceTranslation(locale);
$apiInstance = $client->getInvoiceApi();

$locale = "fr_FR";

$result = $apiInstance->getInvoiceTranslation($locale);

Example Response:


sports-monthly : Voiture Sport

Query Parameters

None.

Response

If successful, returns a status code of 200 and the translation table. A status code of 404 means no table was found for the specified locale.

Template

A template is a document based on mustache that provides the layout information for invoices. When a customer accesses an invoice, the invoice is generated from the system data, formatted using the appropriate template, and translated according to the invoice translations corresponding to the locale of the customer's account if any.

Refer to the Invoice templates document and Internationalization manual for an introduction to the translation process/Kill Bill's internationalization support.

Upload the manualPay invoice template for the tenant

Uploads an invoice template for accounts that have the MANUAL_PAY tag. These accounts manually pay their invoices (e.g. ACH). Typically, this template will contain extra information like the company bank account details, PO number, etc.

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/manualPayTemplate

Example Request:

# specify the template in the request body
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/html" \
    -H "Accept: text/html" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d '"Some_HTML_String"' \
    "http://localhost:8080/1.0/kb/invoices/manualPayTemplate"   

OR 

# specify the template in a separate mustache file
curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H 'X-Killbill-CreatedBy: admin' \
     -H "Content-Type: text/html" \
     -X POST \
     -d @HTMLTemplate-manual-pay.mustache \
     "http://localhost:8080/1.0/kb/invoices/manualPayTemplate"
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

String body = "Test HTML String";
Boolean deleteIfExists = true;
String template = invoiceApi.uploadInvoiceMPTemplate(body, deleteIfExists,requestOptions);

user = "demo"
reason = nil
comment = nil

invoice_template = "Some_HTML_String"
is_manual_pay = true
delete_if_exists = true
KillBillClient::Model::Invoice.upload_invoice_template(invoice_template,
                                                       is_manual_pay,
                                                       delete_if_exists,
                                                       user,
                                                       reason,
                                                       comment,
                                                       options)
invoiceApi = killbill.api.InvoiceApi()

body = 'Some_HTML_String'

invoiceApi.upload_invoice_mp_template(body,
                                      created_by='demo',
                                      reason='reason',
                                      comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const deleteIfExists = true;
const body = 'Some HTML String';

api.uploadInvoiceMPTemplate(body, 'created_by', deleteIfExists);
$apiInstance = $client->getInvoiceApi();

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

$body = "Some HTML String";
$deleteIfExists = true;

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

Request Body

Contains a mustache manual pay template in HTML format. Alternatively, the path of template file can also be specified as the request body.

Query Parameters

Name Type Required Default Description
deleteIfExists boolean no false if true, delete any existing manual pay template

Response

If successful, returns a status code of 201 and a Location header that can be used to retrieve the manual payment invoice template.

Retrieve the manualPay invoice template for the tenant

Retrieves the manual pay invoice template previously uploaded for this tenant, if any.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/manualPayTemplate

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: text/html" \
    "http://localhost:8080/1.0/kb/invoices/manualPayTemplate/"  
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

String locale = "fr_FR";
String template = invoiceApi.getInvoiceMPTemplate(locale, requestOptions);
locale = "fr_FR"
is_manual_pay = true

template = KillBillClient::Model::Invoice.get_invoice_template(is_manual_pay, locale, options)
invoiceApi = killbill.api.InvoiceApi()

locale = 'fr_FR'

template = invoiceApi.get_invoice_mp_template(locale)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const locale = 'fr_FR';

const response: AxiosResponse = await api.getInvoiceMPTemplate(locale);
$apiInstance = $client->getInvoiceApi();

$locale = "fr_FR";

$result = $apiInstance->getInvoiceMPTemplate($locale);

Example Response:

<html>
    <head>
        <style type="text/css">
            th {align=left; width=225px; border-bottom: solid 2px black;}
        </style>
    </head>
    <body>
        <h1>{{text.invoiceTitle}}</h1>
        <table>
            <tr>
                <td rowspan=3 width=350px>Insert image here</td>
                <td width=100px/>
                <td width=225px/>
                <td width=225px/>
            </tr>
            <tr>
                <td />
                <td align=right>{{text.invoiceDate}}</td>
                <td>{{invoice.formattedInvoiceDate}}</td>
            </tr>
            <tr>
                <td />
                <td align=right>{{text.invoiceNumber}}</td>
                <td>{{invoice.invoiceNumber}}</td>
            </tr>
            <tr>
                <td>{{text.companyName}}</td>
                <td></td>
                <td align=right>{{text.accountOwnerName}}</td>
                <td>{{account.name}}</td>
            </tr>
            <tr>
                <td>{{text.companyAddress}}</td>
                <td />
                <td />
                <td>{{account.email}}</td>
            </tr>
            <tr>
                <td>{{text.companyCityProvincePostalCode}}</td>
                <td />
                <td />
                <td>{{account.phone}}</td>
            </tr>
            <tr>
                <td>{{text.companyCountry}}</td>
                <td />
                <td />
                <td />
            </tr>
            <tr>
                <td><{{text.companyUrl}}</td>
                <td />
                <td />
                <td />
            </tr>
        </table>
        <br />
        <br />
        <br />
        <table>
            <tr>
                <th>{{text.invoiceItemBundleName}}</td>
                <th>{{text.invoiceItemDescription}}</td>
                <th>{{text.invoiceItemServicePeriod}}</td>
                <th>{{text.invoiceItemAmount}}</td>
            </tr>
            {{#invoice.invoiceItems}}
            <tr>
                <td>{{description}}</td>
                <td>{{planName}}</td>
                <td>{{formattedStartDate}}{{#formattedEndDate}} - {{formattedEndDate}}{{/formattedEndDate}}</td>
                <td>{{invoice.currency}} {{amount}}</td>
            </tr>
            {{/invoice.invoiceItems}}
            <tr>
                <td colspan=4 />
            </tr>
            <tr>
                <td colspan=2 />
                <td align=right><strong>{{text.invoiceAmount}}</strong></td>
                <td align=right><strong>{{invoice.chargedAmount}}</strong></td>
            </tr>
            <tr>
                <td colspan=2 />
                <td align=right><strong>{{text.invoiceAmountPaid}}</strong></td>
                <td align=right><strong>{{invoice.paidAmount}}</strong></td>
            </tr>
            <tr>
                <td colspan=2 />
                <td align=right><strong>{{text.invoiceBalance}}</strong></td>
                <td align=right><strong>{{invoice.balance}}</strong></td>
            </tr>
        </table>
    </body>
</html>

Query Parameters

None.

Response

If successful, returns a status code of 201 and the manual pay template.

Upload the invoice template for the tenant

Uploads an invoice template for accounts with an automatic payment method (accounts without the MANUAL_PAY tag).

HTTP Request

POST http://127.0.0.1:8080/1.0/kb/invoices/template

Example Request:

# specify the template in the request body
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/html" \
    -H "Accept: text/html" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d "Some_HTML_String" \
    "http://localhost:8080/1.0/kb/invoices/template"    

OR

# specify the template in a separate mustache file
curl -v \
    -X POST \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Content-Type: text/html" \
    -H "Accept: text/html" \
    -H "X-Killbill-CreatedBy: demo" \
    -H "X-Killbill-Reason: demo" \
    -H "X-Killbill-Comment: demo" \
    -d @HTMLTemplate.mustache \
    "http://localhost:8080/1.0/kb/invoices/template?deleteIfExists=true"    
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

String body = "Test HTML String";
Boolean deleteIfExists = true;
String template = invoiceApi.uploadInvoiceTemplate(body, deleteIfExists,requestOptions);
user = "demo"
reason = nil
comment = nil

invoice_template = "Some_HTML_String"
is_manual_pay = false
delete_if_exists = true
KillBillClient::Model::Invoice.upload_invoice_template(invoice_template,
                                                       is_manual_pay,
                                                       delete_if_exists,
                                                       user,
                                                       reason,
                                                       comment,
                                                       options)
invoiceApi = killbill.api.InvoiceApi()

body = 'Some_HTML_String'
delete_if_exists = True

invoiceApi.upload_invoice_template(body,
                                   delete_if_exists=delete_if_exists,
                                   created_by='demo',
                                   reason='reason',
                                   comment='comment')
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const deleteIfExists = true;
const body = 'Some HTML String';

api.uploadInvoiceTemplate(body, 'created_by', deleteIfExists);
$apiInstance = $client->getInvoiceApi();

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

$body = "Some HTML String";
$deleteIfExists = true;

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

Request Body

Contains a mustache automatic pay template in HTML format. Alternatively, the path of template file can also be specified as the request body.

Query Parameters

Name Type Required Default Description
deleteIfExists boolean no false if true, delete any existing manual pay template

Response

If successful, returns a status code of 201 and a Location header that can be used to retrieve the automatic payment invoice template.

Retrieve the invoice template for the tenant

Retrieves the automatic pay invoice template previously uploaded for this tenant, if any.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/template

Example Request:

curl -v \
    -u admin:password \
    -H "X-Killbill-ApiKey: bob" \
    -H "X-Killbill-ApiSecret: lazar" \
    -H "Accept: text/html" \
    "http://localhost:8080/1.0/kb/invoices/template"    
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

String template = invoiceApi.getInvoiceTemplate(requestOptions);
locale = "fr_FR"
is_manual_pay = false

template = KillBillClient::Model::Invoice.get_invoice_template(is_manual_pay, locale, options)
invoiceApi = killbill.api.InvoiceApi()

template = invoiceApi.get_invoice_template()
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const response: AxiosResponse = await api.getInvoiceTemplate();
$apiInstance = $client->getInvoiceApi();

$result = $apiInstance->getInvoiceTemplate();

Example Response:

<html>
    <head>
        <style type="text/css">
            th {align=left; width=225px; border-bottom: solid 2px black;}
        </style>
    </head>
    <body>
        <h1>{{text.invoiceTitle}}</h1>
        <table>
            <tr>
                <td rowspan=3 width=350px>Insert image here</td>
                <td width=100px/>
                <td width=225px/>
                <td width=225px/>
            </tr>
            <tr>
                <td />
                <td align=right>{{text.invoiceDate}}</td>
                <td>{{invoice.formattedInvoiceDate}}</td>
            </tr>
            <tr>
                <td />
                <td align=right>{{text.invoiceNumber}}</td>
                <td>{{invoice.invoiceNumber}}</td>
            </tr>
            <tr>
                <td>{{text.companyName}}</td>
                <td></td>
                <td align=right>{{text.accountOwnerName}}</td>
                <td>{{account.name}}</td>
            </tr>
            <tr>
                <td>{{text.companyAddress}}</td>
                <td />
                <td />
                <td>{{account.email}}</td>
            </tr>
            <tr>
                <td>{{text.companyCityProvincePostalCode}}</td>
                <td />
                <td />
                <td>{{account.phone}}</td>
            </tr>
            <tr>
                <td>{{text.companyCountry}}</td>
                <td />
                <td />
                <td />
            </tr>
            <tr>
                <td><{{text.companyUrl}}</td>
                <td />
                <td />
                <td />
            </tr>
        </table>
        <br />
        <br />
        <br />
        <table>
            <tr>
                <th>{{text.invoiceItemBundleName}}</td>
                <th>{{text.invoiceItemDescription}}</td>
                <th>{{text.invoiceItemServicePeriod}}</td>
                <th>{{text.invoiceItemAmount}}</td>
            </tr>
            {{#invoice.invoiceItems}}
            <tr>
                <td>{{description}}</td>
                <td>{{planName}}</td>
                <td>{{formattedStartDate}}{{#formattedEndDate}} - {{formattedEndDate}}{{/formattedEndDate}}</td>
                <td>{{invoice.currency}} {{amount}}</td>
            </tr>
            {{/invoice.invoiceItems}}
            <tr>
                <td colspan=4 />
            </tr>
            <tr>
                <td colspan=2 />
                <td align=right><strong>{{text.invoiceAmount}}</strong></td>
                <td align=right><strong>{{invoice.chargedAmount}}</strong></td>
            </tr>
            <tr>
                <td colspan=2 />
                <td align=right><strong>{{text.invoiceAmountPaid}}</strong></td>
                <td align=right><strong>{{invoice.paidAmount}}</strong></td>
            </tr>
            <tr>
                <td colspan=2 />
                <td align=right><strong>{{text.invoiceBalance}}</strong></td>
                <td align=right><strong>{{invoice.balance}}</strong></td>
            </tr>
        </table>
    </body>
</html>

Query Parameters

None.

Response

If successful, returns a status code of 201 and the automatic pay template.

Example

The translation and templating process may seem a little complex. Here is a simple example for the use of a template with translation.

  1. To begin, a tenant should upload suitable manual pay and autopay templates reflecting her desired layout for the invoice. If this is not done a default template will be used.

  2. Suppose the tenant does business with German customers. She then should upload translation tables, perhaps provided by customers, designated for the German locale (de_DE). Tables are needed for both invoice items and catalog items. The invoice items to be translated are the names of the fields on the template, such as invoiceTitle, invoiceAmount, etc. The catalog items to be translated are the names for actual items such as product name and plan name. There can be translation tables for any number of distinct locales.

Catalog translation example (German):

gold plan = Goldplan sports car = Sportwagen

Invoice translation example (German):

invoiceTitle = Rechnung invoiceNumber = Rechnungsnumber invoiceBalance = Rechnungssaldo

  1. Each account has a designated locale. When an invoice is retrieved for an account, the invoice is generated using the invoice template and the appropriate translation tables, if any.

Refer to the Invoice Templates Tutorial for a step-by-step tutorial.

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 invoice audit logs with history by invoice id

Retrieve a list of audit log records showing events that occurred involving changes to a specified invoice. History information (a copy of the full invoice object) is included with each record.

Some examples:

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/{invoiceId}/auditLogsWithHistory

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/invoices/d456a9b3-7e48-4f56-b387-1d65a492e75e/auditLogsWithHistory"
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

UUID invoiceId = UUID.fromString("8f6f3405-249f-4b66-a0c2-ee84e884e81d");
AuditLogs logs = invoiceApi.getInvoiceAuditLogsWithHistory(invoiceId, requestOptions);
invoice = KillBillClient::Model::Invoice.new
invoice.invoice_id = "bb9cf385-cc78-46a6-b069-924bdfdeb4f7"

audit_logs = invoice.audit_logs_with_history(options)
invoiceApi = killbill.api.InvoiceApi()

invoice_id = "bb9cf385-cc78-46a6-b069-924bdfdeb4f7"

audit_logs = invoiceApi.get_invoice_audit_logs_with_history(invoice_id)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const invoiceId = 'bb9cf385-cc78-46a6-b069-924bdfdeb4f7';

const response: AxiosResponse<killbill.AuditLog[], any> = await api.getInvoiceAuditLogsWithHistory(invoiceId);
$apiInstance = $client->getInvoiceApi();

$invoiceId = "bb9cf385-cc78-46a6-b069-924bdfdeb4f7";

$result = $apiInstance->getInvoiceAuditLogsWithHistory($invoiceId);

Example Response:

[
  {
    "changeType": "INSERT",
    "changeDate": "2019-02-22T22:38:10.000Z",
    "objectType": "INVOICE",
    "objectId": "d456a9b3-7e48-4f56-b387-1d65a492e75e",
    "changedBy": "SubscriptionBaseTransition",
    "reasonCode": null,
    "comments": null,
    "userToken": "1f03e074-dea1-45c5-aee3-c9464886f476",
    "history": {
      "id": null,
      "createdDate": "2019-02-22T22:38:10.000Z",
      "updatedDate": null,
      "recordId": 2121,
      "accountRecordId": 10,
      "tenantRecordId": 1,
      "accountId": "7b3e14b1-6e76-46d3-bbfd-5a16e5b5eca2",
      "invoiceNumber": null,
      "invoiceDate": "2019-02-22",
      "targetDate": "2019-02-22",
      "currency": "USD",
      "migrated": false,
      "status": "COMMITTED",
      "invoiceItems": [],
      "invoicePayments": [],
      "processedCurrency": "USD",
      "parentInvoice": null,
      "isWrittenOff": false,
      "writtenOff": false,
      "tableName": "INVOICES",
      "historyTableName": "INVOICE_HISTORY"
    }
  }
]

Query Parameters

None.

Response

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

These endpoints allow you to list all invoices or to search for a specific invoice. Note that these endpoints return shallow objects and thus the value 0 is returned for the amount, creditAdj, refundAdj and balance fields. In order to retrieve the actual data for these fields, additional endpoints (like retrieve invoice by id) would need to be invoked.

List invoices

Retrieve a list of all invoice records for this tenant.

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/pagination

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/invoices/pagination"  
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

Long offset = 0L;
Long limit = 1L;
Invoices result = invoiceApi.getInvoices(offset, 
                                         limit, 
                                         AuditLevel.NONE, 
                                         requestOptions);
offset = 0
limit = 100

invoices = KillBillClient::Model::Invoice.find_in_batches(offset,
                        limit,
                        options)
invoiceApi = killbill.api.InvoiceApi()

invoices = invoiceApi.get_invoices()
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const response: AxiosResponse<killbill.Invoice[], any> = await api.getInvoices();
$apiInstance = $client->getInvoiceApi();

$offset = 0;
$limit = 10;
$audit = "NONE";

$result = $apiInstance->getInvoices($offset, $limit, $audit);

Example Response:

[
  {
    "amount": 0,
    "currency": "USD",
    "status": "COMMITTED",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "404a98a8-4dd8-4737-a39f-be871e916a8c",
    "invoiceDate": "2018-07-19",
    "targetDate": "2018-07-19",
    "invoiceNumber": "309",
    "balance": 0,
    "accountId": "8785164f-b5d7-4da1-9495-33f5105e8d80",
    "bundleKeys": null,
    "credits": null,
    "items": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  },
  {
    "amount": 0,
    "currency": "USD",
    "status": "COMMITTED",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "903e55d3-8072-47f1-80fc-32857dbdbcc5",
    "invoiceDate": "2018-07-20",
    "targetDate": "2018-07-20",
    "invoiceNumber": "310",
    "balance": 0,
    "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d",
    "bundleKeys": null,
    "credits": null,
    "items": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  },
  {
    "amount": 0,
    "currency": "USD",
    "status": "VOID",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "18e9b3d9-9083-4725-9e8a-27d3a57c2e88",
    "invoiceDate": "2018-07-20",
    "targetDate": "2018-07-20",
    "invoiceNumber": "311",
    "balance": 0,
    "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d",
    "bundleKeys": null,
    "credits": null,
    "items": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  },
  {
    "amount": 0,
    "currency": "USD",
    "status": "DRAFT",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "c6fe2246-62e2-450d-b9fc-a27003771535",
    "invoiceDate": "2018-07-20",
    "targetDate": "2018-07-20",
    "invoiceNumber": "312",
    "balance": 0,
    "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d",
    "bundleKeys": null,
    "credits": null,
    "items": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  },
  {
    "amount": 0,
    "currency": "USD",
    "status": "DRAFT",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "d6c7b6b9-f048-4266-bde6-4c381e69f432",
    "invoiceDate": "2018-07-20",
    "targetDate": "2018-07-20",
    "invoiceNumber": "313",
    "balance": 0,
    "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d",
    "bundleKeys": null,
    "credits": null,
    "items": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  },
  {
    "amount": 0,
    "currency": "USD",
    "status": "COMMITTED",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "71742c60-273f-4c91-8b8c-7555a3554b0a",
    "invoiceDate": "2018-07-20",
    "targetDate": "2018-07-20",
    "invoiceNumber": "314",
    "balance": 0,
    "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d",
    "bundleKeys": null,
    "credits": null,
    "items": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  },
  {
    "amount": 0,
    "currency": "USD",
    "status": "COMMITTED",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "e8032d7d-4354-46f7-82fa-8e635cc61fc5",
    "invoiceDate": "2018-07-20",
    "targetDate": "2018-07-20",
    "invoiceNumber": "315",
    "balance": 0,
    "accountId": "2ad52f53-85ae-408a-9879-32a7e59dd03d",
    "bundleKeys": null,
    "credits": null,
    "items": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  }
]

Query Parameters

Name Type Required Default Description
offset long no 0 Starting index for items listed
limit long no 100 Maximum number of items to be listed
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 list of all invoices for this tenant.

Search invoices

Search for an invoice by a specified search string. Search operation can be of two types as follows:

Basic:

If the search string is a number, it is compared to the invoiceNumber attribute. An exact match is required. Otherwise, it is compared to the following attributes: invoiceId, accountId, or currency. The operation returns all invoice records in which the search string matches all or part of any one of these attributes.

Advanced:

Advanced search is of two types: Search by fields and Search by balance.

Search by field allows filtering on the specified fields. The prefix marker _q=1 needs to be specified at the beginning of the search key to indicate this is an advanced query.

Search by balance allows filtering based on balance. In addition to the prefix marker _q=1, a balance query pattern (balance=) needs to be specified.

Note that you can either filter by fields or filter by balance, it is not currently possible to do both.

The search key should be in the following format: <field>[<operator>]=value. Here:

Some search by field search key examples: * _q=1&status=DRAFT - Returns invoices in DRAFT status. * _q=1&status=DRAFT&currency[eq]=USD - Returns invoices in DRAFT status where currency is USD.

Some search by balance search key examples:

Note: The symbols [,],% need to be URL encoded while using cURL/Postman as follows:

Symbol Encoding
[ %5B
] %5D
% %25

HTTP Request

GET http://127.0.0.1:8080/1.0/kb/invoices/search/{searchKey}

Example Request:

## Basic Search
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/invoices/search/404a98a8-4dd8-4737-a39f-be871e916a8c" 

## Advanced Search (search by currency & status)  
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/invoices/search/_q=1&currency%5Beq%5D=USD&status%5Beq%5DDRAFT"

## Advanced Search (Search by balance):
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/invoices/search/_q=1&balance%5Beq%5D=200" 
import org.killbill.billing.client.api.gen.InvoiceApi;
protected InvoiceApi invoiceApi;

String searchKey = "1a49101b-305e-4b4d-8403-7377596407b6";

Long offset = 0L;
Long limit = 1L;

Invoices result = invoiceApi.searchInvoices(searchKey, 
                          offset,
                          limit, 
                          AuditLevel.NONE, 
                          requestOptions);
search_key = '3135'
offset = 0
limit = 100

invoices = KillBillClient::Model::Invoice.find_in_batches_by_search_key(search_key,
                                      offset,
                                      limit,
                                      options)
invoiceApi = killbill.api.InvoiceApi()

search_key = 'USD'

invoices = invoiceApi.search_invoices(search_key)
const api: killbill.InvoiceApi = new killbill.InvoiceApi(config);

const searchKey = '8600';

const response: AxiosResponse<killbill.Invoice[], any> = await api.searchInvoices(searchKey);
$apiInstance = $client->getInvoiceApi();

$searchKey = "8600"; //invoice number
$offset = 0;
$limit = 1;
$audit = "NONE";

$result = $apiInstance->searchInvoices($searchKey, $offset, $limit, $audit);

Example Response:

[
  {
    "amount": 0,
    "currency": "USD",
    "status": "COMMITTED",
    "creditAdj": 0,
    "refundAdj": 0,
    "invoiceId": "404a98a8-4dd8-4737-a39f-be871e916a8c",
    "invoiceDate": "2018-07-19",
    "targetDate": "2018-07-19",
    "invoiceNumber": "309",
    "balance": 0,
    "accountId": "8785164f-b5d7-4da1-9495-33f5105e8d80",
    "bundleKeys": null,
    "credits": null,
    "items": [],
    "isParentInvoice": false,
    "parentInvoiceId": null,
    "parentAccountId": null,
    "auditLogs": []
  }
]

Query Parameters

Name Type Required Default Description
offset long none 0 Starting index for items listed
limit long none 100 Maximum number of items to return on this page
audit string no "NONE" Level of audit information to return: "NONE", "MINIMAL" (only inserts), or "FULL"

Response

If successful, returns a list of invoices matched with the specified search key.