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.