PlusWaseDevelopers

Webhooks

PlusWase calls the plugin's REST routes on the connected site, each request signed with the connection's shared secret.

Routes

RequestSent whenBody
POST/wp-json/plw/v1/purgeA product published to the site was saved, published, unpublished, moved to To be removed or restored, or the image domain changed.{ "scope": "all" }
POST/wp-json/plw/v1/verifyThe owner presses Connect.{ "nonce": "<32 hex>" }
POST/wp-json/plw/v1/fulfillment, /trackingNot sent yet; they answer 501 until shipments are tracked in PlusWase.

purge drops the plugin's cached catalog answers, so the site shows the change within a minute. verify answers { "proof": hex HMAC-SHA256(shared secret, "verify.<nonce>") }, which proves the plugin holding this connection's secret runs on the domain.

Signature

HeaderValue
x-plw-timestampUnix seconds when PlusWase sent it.
x-plw-signaturesha256= followed by the hex HMAC-SHA256 of <timestamp>.<raw body> with the shared secret.

Refuse a request whose timestamp is more than 5 minutes away from now, and compare signatures in constant time. This is what the plugin does:

function plw_verify_webhook(WP_REST_Request $req): bool {
    $secret = plw_shared_secret();
    if ($secret === '') return false;
    $sig = (string) $req->get_header('x-plw-signature');
    $ts  = (int) $req->get_header('x-plw-timestamp');
    if ($sig === '' || !$ts || abs(time() - $ts) > 300) return false;
    return hash_equals('sha256=' . hash_hmac('sha256', $ts . '.' . $req->get_body(), $secret), $sig);
}

Delivery