Webhooks in WordPress
The Coinsnap WordPress plugin registers a webhook endpoint that Coinsnap calls when a payment event occurs. This is how the plugin reliably updates WooCommerce order statuses.
Webhook endpoint
The plugin hooks into the WooCommerce API endpoint system:
add_action('woocommerce_api_coinsnap', [ $this, 'processWebhook' ]);
This means the webhook URL is:
https://yoursite.com/?wc-api=coinsnap
On sites with pretty permalinks enabled, WooCommerce also routes this to https://yoursite.com/wc-api/coinsnap/. The plugin registers this URL with Coinsnap automatically when you save settings.
Registering the webhook with Coinsnap
The plugin automatically registers the webhook URL with Coinsnap when you save the plugin settings. You can verify it by going to Coinsnap Dashboard → Webhooks.
If automatic registration fails, add the webhook manually:
- Go to Coinsnap Dashboard → Webhooks → Add Webhook
- Enter the webhook URL (see above)
- Select events: Settled, Expired
- Copy the Signing Secret
- The Signing Secret is stored automatically by the plugin in the
coinsnap_webhookoption (coinsnap_webhook['secret']). If you registered the webhook manually, paste the secret into the plugin settings under WooCommerce → Settings → Coinsnap → Webhook Secret.
Signature verification
The plugin verifies the X-Coinsnap-Sig header before processing any webhook. From AbstractGateway.php:
// Get signature from header
$headers = getallheaders();
$signature = null;
foreach ($headers as $key => $value) {
if (strtolower($key) === 'x-coinsnap-sig') {
$signature = $value;
}
}
if (null === $signature) {
wp_die('Authentication required', '', [ 'response' => 401 ]);
}
// Validate — delegates to Coinsnap\Client\Webhook::isIncomingWebhookRequestValid()
if (! $this->apiHelper->validWebhookRequest($signature, $rawPostData)) {
wp_die('Invalid authentication signature', '', [ 'response' => 401 ]);
}
The webhook secret is read from get_option('coinsnap_webhook')['secret'].
Order status mapping
Default mappings from OrderStates.php (configurable in WooCommerce → Settings → Coinsnap → Order States):
| Webhook event | Default WooCommerce status | Meaning |
|---|---|---|
New | pending | Payment attempt started |
Processing | on-hold | Full payment received, waiting for on-chain settlement |
Settled | completed | Payment settled — trigger fulfillment |
Expired | cancelled | Invoice expired without payment |
The Settled mapping defaults to completed rather than processing. WooCommerce automatically sets virtual/downloadable orders to completed regardless; for physical products you may want to change this to processing so orders enter your fulfillment queue.
All mappings are user-configurable from the settings page.
Debugging webhooks
If orders are not updating after payment:
- Check the Coinsnap dashboard — go to Webhooks → [your webhook] → Deliveries and look for failed deliveries
- Check the webhook URL — confirm the registered URL is reachable from the internet (not
localhost) - Check WordPress debug logs — enable
WP_DEBUG_LOGinwp-config.php:define('WP_DEBUG', true);define('WP_DEBUG_LOG', true); - Redeliver manually — use the Redeliver button in the Coinsnap dashboard to retry a failed delivery
Example webhook payload
{
"type": "Settled",
"invoiceId": "inv_4Kz9mXpQ2rNvBtYwLs8cDf",
"metadata": {
"orderId": "142"
},
"additionalStatus": "None"
}
The metadata.orderId field contains the WooCommerce order ID as passed when creating the invoice. The plugin uses this to look up the WooCommerce order and update its status.