Skip to main content
Outgoing webhooks notify your systems (ERP, Make, n8n, Zapier or your own server) about what happens in Hurry without you having to poll for anything. You register a URL, choose which events you want, and Hurry sends it a POST with the full JSON of the order, payment, customer, store and gateway every time something happens. They’re managed from the CRM, under Account → Webhooks. Only the main account can see and configure them: collaborators don’t have access to this section.

How it works

1

Create an endpoint

Click New endpoint, give it a name, enter your receiver’s https URL and check the events you want to receive. If needed, limit the endpoint to specific stores and add your own headers.
2

Store the secret

When you create it, Hurry shows you a secret in the format whsec_.... Store it in your receiver: you’ll use it to verify the signature of each delivery. You can view it again or rotate it from the endpoint card.
3

Verify the signature and respond 2xx

On each delivery, check the X-Hurry-Signature header against the raw body and respond with a 2xx code within 10 seconds. If you don’t respond 2xx, Hurry retries automatically.
4

Test it

Click Test on the endpoint. Hurry sends a signed ping event and shows you the HTTP code and your server’s response.

Events

Each endpoint subscribes to the events you choose. The event code travels in the JSON type field and in the X-Hurry-Event header.
A checkout sale triggers order.paid and payment.succeeded at the same time. If you only want sales, subscribe to order.paid. If you also want subscription recurring charges, use payment.succeeded.

Store scope

An endpoint can receive events from all stores (including recurring charges, which have no store) or only some. If you choose specific stores, charges without a store aren’t sent to that endpoint.

Custom headers

You can add up to 5 custom headers per endpoint, for example Authorization: Bearer ... if your receiver requires a token. Names can contain letters, numbers and hyphens. You can’t set the headers Hurry defines: Host, Content-Type, Content-Length, Transfer-Encoding, User-Agent or any starting with X-Hurry-.

Event format

All events share the same envelope. What changes is the content of data.
string
Event identifier (evt_ + 24 characters). It’s the same across all endpoints, all retries and manual resends of the same occurrence. Use it to ignore duplicates.
string
Event code: order.paid, payment.failed, refund.created…
string
JSON format version. Currently 2026-11-01. Each endpoint is pinned to the version it was created with.
string
Event creation date in ISO 8601 with time zone.
string
Your Hurry account identifier.
object
id and name of the endpoint receiving the event.
object
Everything known about the occurrence. Which nodes are filled in depends on the event; those that don’t apply come as null.
Amounts and dates. All amounts are integers in the currency’s minor unit (cents: 4980 is 49.80 EUR), with the currency alongside and a readable version in the *Formatted fields. Dates are in ISO 8601 with time offset.

What data contains for each event

string
Order identifier in Hurry.
string
External reference of the cart or source platform.
integer | null
Sequential order number, if already assigned.
string
Readable order name, for example #1001.
string
Order status in the CRM: PENDING, IN_PROGRESS, REQUIRES_ACTION, PAID, PARTIALLY_REFUNDED, REFUNDED or CANCELED. Read the note below before using it to tell whether the order has been paid.
boolean
true if the order has been paid. Derived from the payment, it works for all gateways.
string | null
Time of the charge.
string | null
Status of the associated payment: CREATED, REQUIRES_ACTION, PROCESSING, SUCCEEDED, CANCELED or FAILED.
string
Charge currency (ISO 4217).
object
Charge amounts in minor units: currency, subtotal, tax, shipping, discount, upsells, total and totalFormatted.
object
The same amounts in the currency the buyer saw at checkout, plus fxRate when there was a conversion.
string | null
Discount code applied.
string | null
Name of the chosen shipping option.
array
Order lines. Each with id, productId, sku, name, imageUrl, quantity, unitAmount, taxAmount and totalAmount.
object
Tracking: shipped, shippedAt, trackingNumber and trackingUrl.
string | null
Hurry checkout URL for this order.
string | null
Store page where the purchase started.
string
Direct link to the order in the Hurry CRM.
string
Creation and last modification dates.
order.status is the order status in the CRM and only Shopify stores set it to PAID; on all other gateways it stays at IN_PROGRESS even when the charge has gone through. To know whether an order has been paid, use order.paid, order.paidAt and order.paymentStatus, which come from the payment.
string
Payment identifier in Hurry.
string
CREATED, REQUIRES_ACTION, PROCESSING, SUCCEEDED, CANCELED or FAILED.
integer / string / string
Amount charged in minor units, its currency and the readable version.
integer | null
Amount converted to USD in minor units, if available.
string
Gateway that processed the charge: STRIPE, STRIPE_EVERVAULT, WHOP, ONE, SUMUP, SQUARE, MAMO, AIRWALLEX, SHOPIFY, MOR, SLASH, NEXI, NEXI_ALIAS, REDSYS or REVOLUT.
string | null
Charge identifier in the gateway (for example Stripe’s pi_...).
boolean
true if it’s a recurring charge without an order (rebill).
string | null
Recurring charge batch it belongs to, if applicable.
string | null
Buyer contact. The customer’s is preferred over the one given by the gateway.
object
type, brand, last4, expMonth, expYear, country and funding. The full card number is never sent.
object | null
code and message of the decline when the charge fails.
array
Refunds on the payment, in the same format as data.refund.
integer
Sum of successful or pending refunds, in minor units.
string
Creation and last modification dates.
id, email, name, phone, address (line1, line2, city, state, postalCode, country) and createdAt. It doesn’t include any card data.
shop: id, name, url, slug, customDomain, type (EXTERNAL or NATIVE) and platform (SHOPIFY, WORDPRESS or API).gateway: id, name and psp of the payment credential used for the charge.
id, providerRefundId, amount, currency, amountFormatted, status (PENDING, SUCCEEDED, FAILED or CANCELED), reason, failureReason, createdAt and updatedAt.
string
Identifiers in Hurry and in the gateway.
string
Gateway where it was opened.
string
CHARGEBACK, INQUIRY or EARLY_FRAUD_WARNING.
string
NEEDS_RESPONSE, UNDER_REVIEW, WON, LOST, CHARGE_REFUNDED or CLOSED.
string | null
Previous state, useful in dispute.closed to know where it came from.
string | null
Status and reason as reported by the gateway and the card network.
integer / string / string
Disputed amount.
string | null
Buyer’s email and affected charge in the gateway.
string | null
Opening date, evidence deadline and closing date.
boolean
Whether the gateway has already withdrawn the funds.
string
Link to the risk section of the CRM.
message with fixed text and endpoint with id, name, url and the list of events it’s subscribed to. Use it to check that your receiver is reachable and that you verify the signature correctly.

Full example: order.paid

HTTP headers

Each delivery is a POST with Content-Type: application/json and User-Agent: Hurry-Webhooks/1.0. It also includes these headers: Any custom headers you’ve defined on the endpoint are added to these.

Verify the signature

Each delivery is signed with HMAC-SHA256 using the endpoint’s secret. Verify the signature before trusting the content:
  1. Read the raw request body, exactly as it arrives, before parsing the JSON.
  2. Extract t and v1 from the X-Hurry-Signature header.
  3. Reject the request if t differs by more than 300 seconds from your current time. This way a captured delivery can’t be replayed later.
  4. Compute HMAC-SHA256(secret, t + "." + body) and convert it to lowercase hexadecimal.
  5. Compare the result with v1 in constant time.
Always verify against the raw body. If your framework parses the JSON and serializes it again, the key order or whitespace can change and the signature will no longer match.

Responses, retries and duplicates

Respond 2xx within 10 seconds and process the event afterwards, in the background. Any other response, a timeout or a network failure counts as a failed delivery. Hurry doesn’t follow redirects: a 3xx response also counts as a failure. If a delivery fails, Hurry retries it with increasing waits: the first attempt plus 6 retries, spread over about 9 hours. When all attempts are used up, the delivery is marked Failed and you can resend it manually from Deliveries. Test deliveries (ping) and manual resends are attempted only once.
The same event can arrive more than once. If your server processes the request but the response is lost, Hurry will retry it. Store the id field (or the X-Hurry-Event-Id header) of each processed event and ignore repeats.

Automatic shutdown

To avoid hammering a receiver that’s down, Hurry turns off the endpoint in two cases:
  • 10 consecutive permanent failures: the endpoint switches to Turned off due to failures and we notify you via the CRM bell. A success at any point resets the streak.
  • 410 Gone response: your server says the URL no longer exists and the endpoint is turned off immediately.
When it’s turned off, pending deliveries are marked as failed and nothing new is queued. Once you fix the receiver, turn it back on with the card toggle and resend from Deliveries whatever you want to recover.

Deliveries

In Deliveries you see the history of everything Hurry has sent or tried to send, most recent first, with filters by endpoint and status. Clicking View opens the details with the exact JSON sent, the HTTP code, the first bytes of your server’s response, the duration and the error if there was one. Resend sends the same JSON again with the same event id as a new delivery. History is kept for 30 days.

Secret and security

  • Secret per endpoint. Each endpoint has its own whsec_... secret, encrypted in the database. The list only shows a hint with the last 4 characters. You can view or rotate it whenever you want.
  • Immediate rotation. When you rotate, the previous secret stops working right away: update your receiver with the new one before rotating if you don’t want to lose deliveries.
  • HTTPS and public hosts only. The URL must be https://, point to a public internet domain and not include a username or password. Hurry rejects localhost, internal names, private or loopback addresses and the Hurry platform itself, and checks again before each send.
  • No card data. The JSON never includes the full card number or CVC: only brand, last 4 digits, expiry, country and type.
  • Main account only. Collaborators don’t see the section, and it can’t be changed while impersonating another user.

Limits

Integration with Make, Zapier and n8n

Create a Webhook module or node in the tool, copy the URL it gives you and paste it as the endpoint URL in Hurry. Choose the events and click Test so the tool receives a ping you can use to map the fields. If the tool doesn’t let you verify the signature, add at least one custom header with a token only you and the tool know, and check it in the first step of the flow.

Management from the Hurry MCP

If you use the Hurry MCP connector with an AI assistant, webhooks can also be managed conversationally with these tools. The secret is never returned through the MCP; to view or rotate it you need to use the screen.

Frequently asked questions

Click Test on the endpoint: you’ll see the HTTP code your server returns and its response. Check that the URL is https, public and that you respond 2xx. If Hurry turned it off due to failures, turn it back on with the toggle.
Hurry retries up to 6 times over about 9 hours. If all attempts fail, the delivery is marked as failed and you can resend it from Deliveries. Ten consecutive permanent failures turn off the endpoint and we notify you via the bell.
Yes: create a webhook in that tool, paste its URL into Hurry and choose the events. If you can’t verify the signature, use at least one custom header with a token only you and the tool know.
Full order (status, lines, amounts, discounts, shipping and tracking), payment (status, amount, gateway, method with brand and last 4), customer (email, name, phone, address), store and gateway. Never full card data.
order.status is the order status in the CRM and only Shopify stores set it to PAID. On other gateways, the source of truth for the charge is the payment. Use order.paid, order.paidAt and order.paymentStatus, which work for all of them.
A checkout sale triggers order.paid and payment.succeeded at the same time, with the same content in data. Subscribe to only one of them unless you also want subscription recurring charges, which only arrive as payment.succeeded.
Click Rotate secret: the previous one stops working immediately. Update your receiver with the new one.
Yes, with the card toggle. While paused, no new events are queued; retries already in the queue continue on their normal schedule. When you turn it back on, new events are sent again.