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.
An invoice in DRAFT status is open to receive additional items, and is not considered by the rest of the system when computing account balances or related values.
A COMMITTED invoice is immutable, and its balance is reflected at the Account level. Payments can only happen against COMMITTED invoices.
A VOID invoice is ignored by the rest of the system. A DRAFT or COMMITTED invoice may be voided, but only if there are no successful payments against that invoice. Thus before voiding an invoice, any successful payments need to be refunded.
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:
TARGET_DATE -- Preview the invoice as of the given target date
UPCOMING_INVOICE -- Preview the next scheduled invoice
SUBSCRIPTION_ACTION -- Preview the invoice that would be generated if the specified dryRunAction is taken.
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:
- We cannot VOID an invoice that was partially or fully paid
- We cannot VOID an invoice if it contains positive credit items (
CBA_ADJ
>0), unless such credit was not used, i.e there is enough credit left on the account. - We cannot VOID an invoice if it was repaired, i.e there exists a
REPAIR_ADJ
item pointing to an item inside that invoice.
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:
- When is the next upcoming invoice for a given customer, and what will this invoice contain?
- When is the next upcoming invoice associated with a given subscription or bundle, and what will this invoice contain?
- Given a
targetDate
, what invoice will the system generate? - Given a change in a subscription, such as a new subscription, change of plan, or cancellation, what invoice will the system generate?
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:
- The
effectiveDate
in the body specifies when the action (e.g CREATE) takes place - The
targetDate
as a query parameter specifies the date for the billing, i.e how far in the future we want to bill for. A nulltargetDate
default to now.
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.
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.
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
- 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:
- Assuming the API is invoked after an invoice is generated, it would return one record:
- An
INSERT
record corresponding to the invoice creation
- An
- Assuming the API is invoked after an invoice is voided, it would return two records:
- An
INSERT
record corresponding to the invoice creation - An
UPDATE
record corresponding to the invoice status update
- An
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.
List and Search
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:
field
: The name of the field you want to filter by. Possible values are:- id
- account_id
- invoice_date
- target_date
- currency
- status
- migrated
- parent_invoice
- grp_id
- created_by
- created_date
- updated_by
- updated_date
- balance (applicable only for search by balance)
<operator>
: The comparison operator. This is optional and defaults to the equal to (=) operator if not specified. Possible values are:- and
- eq
- gte
- gt
- like
- lte
- lt
- neq
- or
value
: The value to be used for filtering.
Some search by field search key examples:
* _q=1&status=DRAFT - Returns invoices in DRAFT
status.
* _q=1&status=DRAFT¤cy[eq]=USD - Returns invoices in DRAFT
status where currency is USD
.
Some search by balance search key examples:
- _q=1&balance[eq]=200 - Returns invoices with balance=200.
- _q=1&balance[gt]100 - Returns invoices with balance greater than 100.
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¤cy%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.