Navigation: Spark CRM > Webhooks
Webhooks enable real-time communication from SparkCRM back to your WooCommerce store. When an order status changes in SparkCRM, a webhook event is sent to your WordPress site to update the corresponding WooCommerce order.
Webhook Endpoint
Your site’s webhook URL is displayed on the Spark CRM > Webhooks page:
https://yourstore.com/wp-json/spark/v1/webhookCopy this URL and configure it as a webhook endpoint in your SparkCRM account under Settings > Webhooks.
Webhook Secret
The plugin generates a secret on the Webhooks settings page, where you can also regenerate it. Despite its name it is used as the Basic Authentication password for the Spark CRM webhook - see the note below.
To configure in SparkCRM:
- Copy the Webhook Secret and the Webhook URL from the plugin’s Webhooks page
- In SparkCRM, go to Settings > Webhooks and click Add Webhook
- Paste the plugin’s Webhook URL into Endpoint URL
- Set Authentication to Basic Authentication and paste the Webhook Secret into the password field
- Under Events, select the triggers you want to send
- Add the JSON Payload Parameters the plugin expects for that event (see below)
- Tick Active and save
Use Basic Authentication, not the signature. Spark CRM signs every delivery with HMAC-SHA256 and sends the digest in
X-Webhook-Signature(raw lowercase hex, nosha256=prefix), alongside a delivery id inX-Webhook-ID. This plugin version reads a differently named header,X-Spark-Signature, so it cannot verify Spark CRM’s signature. Because the plugin generates a webhook secret when it is activated, it rejects any request that arrives withoutX-Spark-Signature— so a webhook configured for signature verification returns 401 on every delivery. Basic Authentication is the path the plugin actually supports, and is what its own setup card instructs.
Supported Events
Two names matter here, and they are not the same:
- The trigger you select under Events in Spark CRM. These are snake_case
(
order_complete,refund_created) and never dot-separated. - The
event_typevalue the plugin dispatches on. These are dot-separated (order.approved), and the plugin acts on nothing else — any other value returnsEvent type not handledand the order is untouched.
The plugin does not translate between them. You bridge the two by adding a JSON Payload
Parameter named event_type whose value is the dotted string, and nesting the order
fields under a data object — the plugin reads its fields from body.data, not from the
flat payload Spark CRM sends by default.
| Select this trigger | Set event_type to |
WooCommerce action |
|---|---|---|
order_complete |
order.approved |
Order status set to Processing |
order_declined |
order.declined |
Order status set to Failed |
refund_created |
order.refunded |
WooCommerce refund created |
order_canceled |
order.cancelled |
Order cancelled, stock restored |
fulfillment_created or tracking_updated |
order.shipped |
Order set to Completed; tracking number, tracking URL and carrier stored as order meta |
delivered |
order.delivered |
Delivery recorded in order meta (_spark_delivered_date) plus an order note |
subscription_created |
subscription.created |
Subscription data stored in order meta |
subscription_canceled |
subscription.cancelled |
Subscription status updated |
Note the spelling difference across the boundary: the Spark CRM triggers use the
American single-l canceled, while the plugin’s event_type values use cancelled.
Notes on these events:
- Subscription rebills emit
subscription_rebill_completerather thanorder_complete, and rebill declines deliberately emitsubscription_rebill_declinedinstead oforder_declined. Usetransaction_approvedif you need per-transaction granularity. - A queued
order_declineddelivery is skipped if the order is no longer declined when it is sent, and a queuedsubscription_canceleddelivery is skipped if the subscription is no longer cancelled. refund_createdcarriesrefund_amount,refund_currency,refund_is_partial,refund_transaction_number,refunded_transaction_numberandrefunded_products[], which is what the plugin needs to mirror a partial refund.- All fulfillment events share the same payload shape (
fulfillment_number,tracking_number,carrier,status,shipping_method);tracking_numberis populated once tracking exists, sofulfillment_createdmay carry an empty one. deliveredrequires Enhanced Shipping Notifications on your team before it can be selected. Its payload is fulfillment-scoped (fulfillment_number,tracking_number,carrier,status) and the delivery time comes from the payload’stimestampfield. The plugin looks for adelivered_atfield, so map one in your payload parameters if you want the real delivery date recorded rather than the time the webhook arrived.subscription_createdpayload fields includesubscription_number,status,amount,currency,billing_interval,next_billing_at,trial_days,trial_ends_atandproducts[]. Note thatorder_idholds an order number for the customer’s most recent order, which is not guaranteed to be the order that created the subscription — match onsubscription_numberinstead.
Order Matching
Webhooks match SparkCRM orders to WooCommerce orders using the _spark_order_number meta key, which is stored when an order is first synced to SparkCRM.
Testing
A test endpoint is available to verify your webhook configuration:
GET https://yourstore.com/wp-json/spark/v1/webhook/testThis returns a success response without processing any data.
Troubleshooting
Webhooks Not Arriving
- Verify the endpoint URL is correct in SparkCRM
- Check that your site is accessible from the internet (not localhost)
- Ensure no firewall or security plugin is blocking the REST API endpoint
- Test the endpoint manually using the test URL above
Every Delivery Returns 401
This is what happens when the webhook is configured for signature verification. The plugin
verifies X-Spark-Signature, which Spark CRM never sends — it sends
X-Webhook-Signature — and because the plugin generates a secret when it is activated, it
refuses any request that arrives without its own header.
- Set Authentication to Basic Authentication on the Spark CRM webhook and use the plugin’s Webhook Secret as the password
- Do not use the plugin secret as a signing secret; the two schemes are not interoperable in this plugin version
- Check that no proxy or CDN is stripping the
Authorizationheader
Deliveries Return 200 but Nothing Changes
The plugin answers Event type not handled and returns 200 when it does not recognise the
event_type value. Add a JSON Payload Parameter named event_type set to the dotted
value for that trigger (see Supported Events), and nest the order
fields under a data object.
Order Not Updating
- Confirm the order was originally synced from this WooCommerce site
- Check that the
_spark_order_numbermeta exists on the WooCommerce order - Enable debug mode to see detailed webhook processing logs

