Skip to main content

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:

  1. Go to Coinsnap Dashboard → Webhooks → Add Webhook
  2. Enter the webhook URL (see above)
  3. Select events: Settled, Expired
  4. Copy the Signing Secret
  5. The Signing Secret is stored automatically by the plugin in the coinsnap_webhook option (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 eventDefault WooCommerce statusMeaning
NewpendingPayment attempt started
Processingon-holdFull payment received, waiting for on-chain settlement
SettledcompletedPayment settled — trigger fulfillment
ExpiredcancelledInvoice 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:

  1. Check the Coinsnap dashboard — go to Webhooks → [your webhook] → Deliveries and look for failed deliveries
  2. Check the webhook URL — confirm the registered URL is reachable from the internet (not localhost)
  3. Check WordPress debug logs — enable WP_DEBUG_LOG in wp-config.php:
    define('WP_DEBUG', true);
    define('WP_DEBUG_LOG', true);
  4. 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.