API Documentation

Endpoints

Coupons

Affiliate coupons, with balances, stats and referred orders. Reads go through the same functions the affiliate dashboard uses, so caps, rounding and commission rules always match what affiliates see.

List coupons

GET /wp-json/wcusage/v2/coupons

Permission: admin, read scope.

ParamTypeDescription
user_idintegerOnly coupons assigned to this affiliate. Omit for every assigned affiliate coupon.
searchstringMatch against the coupon code.
page / per_pageintegerStandard pagination.

Returns published coupons that have an affiliate assigned, newest first. Coupons with no assigned affiliate are never listed.

Get one coupon

GET /wp-json/wcusage/v2/coupons/{id}

Permission: admin, the assigned affiliate, or their multi-level upline (PRO). read scope.

{
  "id": 8338,
  "code": "sarah10",
  "user_id": 1456,
  "user": { "id": 1456, "display_name": "Sarah J" },
  "date_created": "2023-05-02T10:11:12",
  "unpaid_commission": 40.46,
  "pending_order_commission": 0,
  "pending_payout_commission": 0,
  "stats": {
    "orders_count": 19, "total_sales": 1977.80, "total_discount": 197.78,
    "total_shipping": 0, "total_commission": 181.60, "last_refreshed": "2026-08-01T02:00:00"
  },
  "commission": { "percent": 10, "percent_override": "", "fixed_per_order": "", "fixed_per_product": "" },
  "referral_url": "https://example.com/affiliate-dashboard/?couponid=sarah10"
}
FieldDescription
unpaid_commissionCommission earned, cleared, and not yet paid out or requested.
pending_order_commissionCommission on orders still inside the pending period (not yet payable).
pending_payout_commissionCommission tied up in payouts that have been requested but not paid.
commission.percentThe percentage rate resolved for this coupon: its own override if it has one, otherwise the store's default rate.
commission.percent_overrideThe per-coupon override itself. Empty when the coupon inherits the store default.
commission.fixed_per_orderFixed amount per referred order, if configured. Empty when unused.
commission.fixed_per_productFixed amount per product, if configured. Empty when unused.
referral_urlThe affiliate's referral URL for this coupon, pointing at the affiliate dashboard page.
stats.last_refreshedWhen the stored snapshot was last rebuilt, or null if it never has been.

Draft and private coupons are addressable — a coupon does not have to be published to have an affiliate and a balance. Trashed and auto-draft coupons answer 404.

Note
Always reference coupons by ID. WooCommerce coupon codes are case-insensitive and not guaranteed unique, and the stats layer is keyed by code — see code_ambiguous below.

Coupon stats

GET /wp-json/wcusage/v2/coupons/{id}/stats

Permission: admin, owner, or MLA upline. read scope; refresh=true additionally needs write.

ParamTypeDescription
from / todateOptional range. Without dates, the stored all-time snapshot is returned (fast). With dates, the range is calculated from the orders.
refreshbooleanRecalculate the all-time figures from the orders and save the result. Default false. Ignored when a date range is given, since those are always calculated.
{
  "coupon_id": 8338,
  "code": "sarah10",
  "from": null,
  "to": null,
  "source": "cache",
  "code_ambiguous": false,
  "orders_count": 19,
  "total_sales": 1977.80,
  "total_discount": 197.78,
  "total_shipping": 0,
  "total_commission": 181.60,
  "status_counts": { "Completed": 17, "Refunded": 2 },
  "last_refreshed": "2026-08-01T02:00:00",
  "unpaid_commission": 40.46,
  "pending_order_commission": 0,
  "pending_payout_commission": 0
}
FieldDescription
sourcecache — the stored snapshot or a short-lived cached calculation. live — freshly calculated for this request. throttled — a rebuild was wanted but the per-coupon budget was spent, so the stored snapshot was returned instead.
code_ambiguoustrue when another published coupon answers to the same code. The stats layer is keyed by code, so figures for this coupon are not reliably addressable and are never saved back to it.
status_countsOrder counts by display status name, e.g. {"Completed": 17}. An empty object when the figures came from the stored snapshot, which holds no breakdown.
last_refreshednull for ranged requests — those are always calculated, so there is no "last refreshed" moment to report.

The response shape is stable regardless of which path answered: status_counts and last_refreshed are always present, even when empty.

Warning
refresh=true is a write wearing a GET's clothes — it rescans the coupon's entire order history and saves the result. A read-only key gets 403 wcusage_api_insufficient_scope; it still receives figures from the stored snapshot on an ordinary request.

Referred orders

GET /wp-json/wcusage/v2/coupons/{id}/orders

Permission: admin, owner, or MLA upline. read scope.

ParamTypeDescription
from / todateOptional date range.
statusstringOrder status slug without the wc- prefix, e.g. completed.
page / per_pageintegerStandard pagination.
[
  {
    "order_id": 8355,
    "date": "2023-07-28T12:46:58",
    "status": "completed",
    "total": 179.80,
    "discount": 17.98,
    "commission": 16.18
  }
]

Newest first. Only orders that actually counted towards this coupon are listed — an order that used the code but was later reassigned to another affiliate is excluded, which keeps this endpoint consistent with /stats.

One request considers at most 5,000 orders (the newest ones). When that cap is hit, the response carries the header X-WCUsage-Truncated: 1, so a client can tell a capped total from a real one. Raise it with the wcusage_api_max_order_rows filter if your program needs a deeper window.

Note
Order rows deliberately carry no customer data — only IDs, totals and commission. A trusted server-side integration can add fields with the wcusage_api_order_item filter.