localhost, not the public internet. This page covers the patterns for getting webhook events to a local development environment, generating test events, validating signature verification, and inspecting deliveries.
The audience is partner integration developers building or debugging webhook handlers. The patterns work for any framework — the examples use Node.js, but the principles apply equally to Python, Ruby, Go, etc.
What you’ll need
Don’t try to test webhooks against a production customer’s account during development. Use the dedicated developer organization to keep test traffic isolated.
Step 1: expose your local server over HTTPS
The webhook subscription’snotificationUrl must be HTTPS — Raise won’t deliver to plain HTTP. The simplest path: a tunneling tool that proxies a public HTTPS URL to your local server.
Using ngrok
https://abc123.ngrok.io. This URL forwards to your localhost:3000. Use it as the webhook’s notificationUrl.
JavaScript
Other tunneling options
Pick whichever fits your team’s workflow. The principle is the same — get a public HTTPS URL that forwards to your local server.
Important: tunnel URLs change
Most tunneling tools assign a fresh URL each time you restart the tunnel (ngrok’s free tier rotates URLs). After every tunnel restart, update the webhook subscription’snotificationUrl via PUT /api/Webhook/{id}.
A common dev-loop pattern: a small script that starts the tunnel, captures the new URL, and updates the webhook subscription automatically:
JavaScript
Step 2: deploy the receiver
Your local webhook receiver needs to:- Listen on the local port the tunnel forwards to.
- Verify the signature on incoming requests.
- Acknowledge quickly with
200 OK. - Process (or queue for processing) the event.
JavaScript
x-raise-signature above) and the algorithm (sha256/hex) are placeholders — confirm against actual deliveries before relying on them. See Signature Verification.
Step 3: trigger test events
The fastest way to generate webhook events: submit test-mode donations throughPOST /api/Raise/give. Each successful submission fires the events your subscription is listening for.
Generate a test payment method
cURL
paymentMethodId usable for test-mode submissions. Re-use the same token across many test donations.
Submit a test donation
JavaScript
Generate other event types
Different event types fire from different actions:
A small test script that generates one event of each type is useful for development — every time you start working on the integration, run the script to confirm webhooks still flow end-to-end.
Step 4: verify what arrives
For each test event, confirm two things: the event arrived at your local receiver, and Raise considers it successfully delivered.Local receiver inspection
Your local receiver should log every incoming event. Inspect the logs to confirm:- The event arrived
- The signature verified
- The payload shape matches what you expected
- Your processing logic ran without errors
Raise-side log inspection
Raise’s webhook log endpoints show the platform’s view of the delivery:cURL
If your receiver logs the event but the Raise log shows
success: "No", the issue is in your response — likely a status code other than 200 or a delayed response that exceeded Raise’s timeout.
If the Raise log shows success: "Yes" but your receiver doesn’t log the event, the receiver isn’t reachable at the URL configured (likely a tunneling issue).
Step 5: troubleshoot delivery
The most common local-dev issues and how to diagnose them:“I’m not receiving any events”
”I’m receiving events but signature verification fails”
”Raise shows success but my receiver returned an error”
IfhttpStatusCode in the Raise log shows 200 but your local logs show errors, the response was sent before the error happened. Common cause: async processing inside the request handler — res.status(200) returns before the actual processing fails.
This is actually the correct pattern (acknowledge quickly, process asynchronously) — the “error” is downstream of the webhook reception. Investigate the processing pipeline separately.
”Multiple log entries for the same event”
IfGET /api/Webhook/{id}/log/list shows multiple entries with the same contextId, Raise retried the delivery. Check the timestamps:
- If the first attempt failed (
success: "No") and the second succeeded (success: "Yes"), retry worked correctly. - If multiple attempts all failed, the receiver is consistently failing — investigate the receiver-side logs for the cause.
Multi-customer testing
For partner integrations that serve multiple customers, test the multi-customer dispatch logic locally:JavaScript
notificationUrl includes the customer ID in the path. The receiver looks up the per-customer secret to verify the signature.
For testing this locally, create multiple test webhook subscriptions — one per simulated customer — each pointing at a different path under the same tunnel URL.
Capturing payloads for offline testing
Once you’ve confirmed end-to-end webhook delivery works, capture real payloads for offline testing. Save them to fixture files and replay them through your processing logic without needing the tunnel.JavaScript
JavaScript
Cleaning up after development
When you’re done with a development session:1
Stop the tunnel
Free the port and disconnect the tunnel to avoid leaving an open public URL pointing at your machine.
2
Set the subscription to inactive
PUT /api/Webhook/{id} with status: 2 to pause event delivery until your next session. This prevents events from queuing up at a tunnel URL that no longer works.3
Or delete the subscription entirely
If the work is complete,
DELETE /api/Webhook/{id} to remove the subscription. Keeps the customer’s webhook subscription list clean.4
Rotate the secret if it was committed to source control
Dev secrets often leak into source control by accident. If your secret was ever in a commit, generate a new one and update via
PUT /api/Webhook/{id}.Where to go next
Signature Verification
The verification pattern you’re testing locally.
Idempotency and Safe Reprocessing
Test the dedup logic by re-firing the same event.
Retry Behavior
Simulate retry scenarios locally by returning
5xx from the receiver.Process a Donation
The donation flow that fires the events you’re testing.