API Documentation

Integrations

Code Samples

Nothing here needs a client library — the API is plain HTTP with a bearer token. These are complete, working starting points.

Note
The samples on this page are illustrative and provided as is. They deliberately keep to the shortest thing that works, so they omit the logging, retry policy, input validation and secret handling a production integration needs. Review and adapt them before relying on them — see Security & Disclaimers.

PHP (inside WordPress)

Talking to another store from a WordPress site, using the HTTP API that is already loaded:

$response = wp_remote_get(
    'https://example.com/wp-json/wcusage/v2/reports/summary?top=5',
    array(
        'timeout' => 15,
        'headers' => array(
            'Authorization' => 'Bearer ' . WCUSAGE_API_KEY,
            'Accept'        => 'application/json',
        ),
    )
);

if ( is_wp_error( $response ) ) {
    error_log( 'Coupon Affiliates API unreachable: ' . $response->get_error_message() );
    return;
}

$code = wp_remote_retrieve_response_code( $response );
$body = json_decode( wp_remote_retrieve_body( $response ), true );

if ( 200 !== $code ) {
    // Every plugin error carries a machine-readable code.
    error_log( 'API error ' . $code . ': ' . ( $body['code'] ?? 'unknown' ) );
    return;
}

printf( 'Unpaid commission: %s %.2f', $body['currency'], $body['totals']['unpaid_commission'] );

PHP (standalone, with pagination)

Walking a collection to the end, using the pagination headers rather than guessing:

<?php
function wcu_api_get( $path, $params = [] ) {
    $url = 'https://example.com/wp-json/wcusage/v2' . $path;
    if ( $params ) {
        $url .= '?' . http_build_query( $params );
    }

    $ch = curl_init( $url );
    curl_setopt_array( $ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER         => true,
        CURLOPT_HTTPHEADER     => [ 'Authorization: Bearer ' . getenv( 'WCUSAGE_KEY' ) ],
        CURLOPT_TIMEOUT        => 20,
    ] );

    $raw         = curl_exec( $ch );
    $status      = curl_getinfo( $ch, CURLINFO_RESPONSE_CODE );
    $header_size = curl_getinfo( $ch, CURLINFO_HEADER_SIZE );
    curl_close( $ch );

    $headers = substr( $raw, 0, $header_size );
    $body    = json_decode( substr( $raw, $header_size ), true );

    $pages = 1;
    if ( preg_match( '/^X-WP-TotalPages:\s*(\d+)/mi', $headers, $m ) ) {
        $pages = (int) $m[1];
    }

    return [ 'status' => $status, 'body' => $body, 'pages' => $pages ];
}

$page = 1;
do {
    $result = wcu_api_get( '/affiliates', [ 'page' => $page, 'per_page' => 100 ] );

    if ( 200 !== $result['status'] ) {
        throw new RuntimeException( 'API error: ' . ( $result['body']['code'] ?? $result['status'] ) );
    }

    foreach ( $result['body'] as $affiliate ) {
        printf( "%-30s %8.2f unpaid\n",
            $affiliate['user']['display_name'],
            $affiliate['unpaid_commission']
        );
    }

    $page++;
} while ( $page <= $result['pages'] );

JavaScript / Node

Including the one piece of error handling that matters most in practice — honouring retry_after:

const BASE = 'https://example.com/wp-json/wcusage/v2';
const KEY  = process.env.WCUSAGE_KEY;

async function api( path, params = {} ) {
  const url = new URL( BASE + path );
  Object.entries( params ).forEach( ( [ k, v ] ) => url.searchParams.set( k, v ) );

  const res  = await fetch( url, { headers: { Authorization: `Bearer ${KEY}` } } );
  const body = await res.json();

  if ( res.status === 429 ) {
    const wait = ( body?.data?.retry_after ?? 60 ) * 1000;
    await new Promise( r => setTimeout( r, wait ) );
    return api( path, params );           // one retry after the window
  }

  if ( ! res.ok ) {
    throw new Error( `${body.code}: ${body.message}` );
  }

  return { body, total: Number( res.headers.get( 'X-WP-Total' ) || 0 ) };
}

const { body: me } = await api( '/me' );
console.log( `Authenticated as ${me.user.display_name}, admin: ${me.is_admin}, scopes:`, me.auth.scopes );

Python

import os, requests

BASE = "https://example.com/wp-json/wcusage/v2"
SESSION = requests.Session()
SESSION.headers["Authorization"] = f"Bearer {os.environ['WCUSAGE_KEY']}"

def get(path, **params):
    r = SESSION.get(f"{BASE}{path}", params=params, timeout=20)
    if r.status_code != 200:
        raise RuntimeError(f"{r.status_code} {r.json().get('code', '')}")
    return r

# All referred orders for one coupon last month, newest first.
page, orders = 1, []
while True:
    r = get("/coupons/8338/orders", **{"from": "2026-07-01", "to": "2026-07-31",
                                       "page": page, "per_page": 100})
    orders += r.json()
    if r.headers.get("X-WCUsage-Truncated") == "1":
        print("Warning: order window was capped; narrow the date range.")
    if page >= int(r.headers.get("X-WP-TotalPages", 1)):
        break
    page += 1

print(f"{len(orders)} orders, {sum(o['commission'] for o in orders):.2f} commission")

Command line

# Quick health check
curl -s https://example.com/wp-json/wcusage/v2/me \
  -H "Authorization: Bearer $WCUSAGE_KEY" | jq

# Top 5 affiliates by all-time commission
curl -s "https://example.com/wp-json/wcusage/v2/reports/summary?top=5" \
  -H "Authorization: Bearer $WCUSAGE_KEY" \
  | jq -r '.top_affiliates[] | "\(.user.display_name)\t\(.total_commission)"'

# Anything that needs paying out
curl -s "https://example.com/wp-json/wcusage/v2/payouts?status=pending&per_page=100" \
  -H "Authorization: Bearer $WCUSAGE_KEY" \
  | jq -r '.[] | "#\(.id)\t\(.user.display_name)\t\(.amount)\t\(.method)"'
Tip
Keep the key in an environment variable or your platform's secret store, never in the script. If a key does leak, revoke it on the API screen — the WordPress account behind it is untouched.