Premium This is a Aviate feature.

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

Coupon Attributes Reference

Each coupon is defined by the following fields:

Field Type Required? Default Description

redemptionCode

string

Yes

Unique code that customers use to apply the discount.

reusable

boolean

Yes

Whether the same customer can redeem the coupon more than once.

discountType

enum

Yes

DISCOUNT_TYPE_FIXED or DISCOUNT_TYPE_PERCENTAGE.

discountPrice

string

If FIXED

Fixed discount amount (e.g., "10.00").

discountCurrency

string

If FIXED

Currency for the fixed discount (e.g., "USD").

discountPercentage

double

If PERCENTAGE

Percentage off (e.g., 20.0 = 20%).

maxUse

int

No

0 (unlimited)

Maximum total redemptions across all customers.

expirationDate

datetime

No

null (never)

ISO 8601 date/time after which redemption is rejected.

planList

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 useCount increments after each successful redemption.

  • Archived coupons return an error when a redemption is attempted.

  • Expired coupons are rejected at redemption time.

Common Pitfalls

  1. Plan-scoped coupon applied to a different plan — the coupon is silently ignored and no discount appears on the invoice. Double-check the planList values match the subscription’s planName.

  2. Using a coupon after its expirationDate — the API returns an error. Update or create a new coupon with a later expiration.

  3. Forgetting enableCouponsApis=true — all coupon endpoints return 404 Not Found. Ensure the system property is set before starting Kill Bill.

  4. Using DISCOUNT_TYPE_FIXED without discountPrice — the API returns 400 Bad Request. Both discountPrice and discountCurrency are required for fixed-amount coupons.

  5. 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

POST

/plugins/aviate-plugin/v1/coupon

Create a coupon.

GET

/plugins/aviate-plugin/v1/coupon

List coupons. Query params: includeArchived, includeExpired.

GET

/plugins/aviate-plugin/v1/coupon/redemptionCode/{code}

Get a coupon by its redemption code.

PUT

/plugins/aviate-plugin/v1/coupon/{code}/archive

Archive (soft-delete) a coupon.