Overview
As a billing administrator or marketing manager, you need to offer discounts to attract new customers, incentivize plan upgrades, or run seasonal promotions. Aviate Coupons let you create reusable discount codes — fixed-amount ($10 off) or percentage-based (20% off) — and optionally restrict them to specific plans or set expiration dates. When a customer redeems a coupon during subscription creation, the discount is automatically applied to their invoice.
This guide walks through creating, retrieving, listing, and archiving coupons, and shows how to apply a coupon when creating a subscription.
Prerequisites
-
A running Kill Bill instance with the Aviate plugin installed.
-
The coupon feature flag enabled — start Kill Bill with the following system property:
com.killbill.billing.plugin.aviate.enableCouponsApis=trueFor details on setting configuration properties, refer to the Kill Bill Configuration Guide.
-
A valid JWT ID token (see Aviate Authentication).
-
At least one plan in the catalog (see Aviate Catalog Guide).
Coupon Attributes Reference
Each coupon is defined by the following fields:
| Field | Type | Required? | Default | Description |
|---|---|---|---|---|
|
string |
Yes |
— |
Unique code that customers use to apply the discount. |
|
boolean |
Yes |
— |
Whether the same customer can redeem the coupon more than once. |
|
enum |
Yes |
— |
|
|
string |
If FIXED |
— |
Fixed discount amount (e.g., |
|
string |
If FIXED |
— |
Currency for the fixed discount (e.g., |
|
double |
If PERCENTAGE |
— |
Percentage off (e.g., |
|
int |
No |
0 (unlimited) |
Maximum total redemptions across all customers. |
|
datetime |
No |
null (never) |
ISO 8601 date/time after which redemption is rejected. |
|
string[] |
No |
[] (all plans) |
Restrict the coupon to specific plan names. |
Create a Percentage Coupon (Step-by-Step)
This section walks through the full lifecycle: create a 20%-off coupon, verify it, apply it to a new subscription, and confirm the discount appears on the invoice.
Step 1: Create the Coupon
curl -v -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
-d '{
"redemptionCode": "WELCOME20",
"reusable": false,
"maxUse": 100,
"discountType": "DISCOUNT_TYPE_PERCENTAGE",
"discountPercentage": 20.0,
"expirationDate": "2026-06-30T23:59:59Z",
"planList": ["starter-monthly"]
}' \
http://127.0.0.1:8080/plugins/aviate-plugin/v1/coupon
Expected Response (HTTP 201)
{
"redemptionCode": "WELCOME20",
"reusable": false,
"maxUse": 100,
"useCount": 0,
"discountType": "DISCOUNT_TYPE_PERCENTAGE",
"discountPercentage": 20.0,
"expirationDate": "2026-06-30T23:59:59Z",
"planList": ["starter-monthly"],
"archived": false
}
Step 2: Verify the Coupon Exists
curl -H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
http://127.0.0.1:8080/plugins/aviate-plugin/v1/coupon/redemptionCode/WELCOME20
Expected Response (HTTP 200)
{
"redemptionCode": "WELCOME20",
"reusable": false,
"maxUse": 100,
"useCount": 0,
"discountType": "DISCOUNT_TYPE_PERCENTAGE",
"discountPercentage": 20.0,
"expirationDate": "2026-06-30T23:59:59Z",
"planList": ["starter-monthly"],
"archived": false
}
Step 3: Apply During Subscription Creation
To redeem a coupon, pass it as a pluginProperty when creating a subscription through the Kill Bill API:
curl -v -X POST -u admin:password \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
-H "X-Killbill-CreatedBy: admin" \
-H "Content-Type: application/json" \
-d '{
"accountId": "e5d3d5b5-4415-4166-b57f-33ca00a59e88",
"planName": "starter-monthly",
"pluginProperty": [
{
"key": "aviate-redemption-code",
"value": "WELCOME20"
}
]
}' \
"http://127.0.0.1:8080/1.0/kb/subscriptions"
|
Important
|
The plugin property key must be exactly aviate-redemption-code. The value is the coupon’s redemptionCode.
|
Expected Response (HTTP 201)
The response is a standard Kill Bill subscription object. A Location header contains the URI of the new subscription.
Step 4: Verify Discount on Invoice
Retrieve the account’s invoices to confirm the discount was applied:
curl -u admin:password \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
"http://127.0.0.1:8080/1.0/kb/accounts/e5d3d5b5-4415-4166-b57f-33ca00a59e88/invoices?withItems=true"
Expected Invoice Items
The invoice should contain two relevant line items — the recurring charge and the coupon discount:
[
{
"itemType": "RECURRING",
"planName": "starter-monthly",
"amount": 10.00
},
{
"itemType": "ITEM_ADJ",
"description": "Coupon: WELCOME20",
"amount": -2.00
}
]
|
Tip
|
In this example the plan costs $10/month and the 20% coupon produces a $2.00 discount. |
Create a Fixed-Amount Coupon
For a flat discount (e.g., $10 off), use DISCOUNT_TYPE_FIXED and supply discountPrice and discountCurrency:
curl -v -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
-d '{
"redemptionCode": "SAVE10",
"reusable": true,
"maxUse": 50,
"discountType": "DISCOUNT_TYPE_FIXED",
"discountPrice": "10.00",
"discountCurrency": "USD",
"expirationDate": "2026-12-31T23:59:59Z"
}' \
http://127.0.0.1:8080/plugins/aviate-plugin/v1/coupon
Expected Response (HTTP 201)
{
"redemptionCode": "SAVE10",
"reusable": true,
"maxUse": 50,
"useCount": 0,
"discountType": "DISCOUNT_TYPE_FIXED",
"discountPrice": "10.00",
"discountCurrency": "USD",
"expirationDate": "2026-12-31T23:59:59Z",
"planList": [],
"archived": false
}
|
Note
|
Because no planList is specified, this coupon can be applied to any plan.
|
List and Manage Coupons
List Active Coupons
curl -H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
http://127.0.0.1:8080/plugins/aviate-plugin/v1/coupon
List All Coupons (Including Archived and Expired)
curl -H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
"http://127.0.0.1:8080/plugins/aviate-plugin/v1/coupon?includeArchived=true&includeExpired=true"
Archive a Coupon
Archiving soft-deletes a coupon so it can no longer be redeemed:
curl -v -X PUT \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
http://127.0.0.1:8080/plugins/aviate-plugin/v1/coupon/WELCOME20/archive
What to Verify
After completing the steps above, confirm the following:
-
The invoice shows a discount line item with the correct amount (percentage or fixed).
-
The coupon’s
useCountincrements after each successful redemption. -
Archived coupons return an error when a redemption is attempted.
-
Expired coupons are rejected at redemption time.
Common Pitfalls
-
Plan-scoped coupon applied to a different plan — the coupon is silently ignored and no discount appears on the invoice. Double-check the
planListvalues match the subscription’splanName. -
Using a coupon after its
expirationDate— the API returns an error. Update or create a new coupon with a later expiration. -
Forgetting
enableCouponsApis=true— all coupon endpoints return404 Not Found. Ensure the system property is set before starting Kill Bill. -
Using
DISCOUNT_TYPE_FIXEDwithoutdiscountPrice— the API returns400 Bad Request. BothdiscountPriceanddiscountCurrencyare required for fixed-amount coupons. -
Applying multiple coupons — only the first coupon is applied. If you need to stack discounts, combine them into a single coupon or use wallet credits instead.
API Reference
| Method | Path | Description |
|---|---|---|
|
|
Create a coupon. |
|
|
List coupons. Query params: |
|
|
Get a coupon by its redemption code. |
|
|
Archive (soft-delete) a coupon. |
Related
-
Aviate Authentication — obtain the
ID_TOKENused in all examples above -
Aviate Billing Accounts — set up accounts before creating subscriptions
-
Aviate Catalog Guide — create the plans referenced by coupons
-
Aviate Wallets — wallet credits as an alternative to coupon discounts