Webhooks let you receive real-time notifications when events occur in your Neutron account — primarily transaction status changes. Instead of polling the API, Neutron pushes updates directly to your server.
How It Works
- Register a webhook —
POST /api/v2/webhookwith your callback URL and secret - Transaction changes — Neutron sends a POST request to your callback URL
- Verify the signature — validate using your webhook secret
- Respond with 200 — acknowledge receipt
Setting Up a Webhook
1. Create a Webhook
Register your callback URL and a secret used for signature verification:
{
"callback": "https://yourapp.com/webhooks/neutron",
"secret": "your-webhook-secret-key"
}Response:
{
"id": "01e2a3dc-0c34-4e14-92e4-b270c4778d95",
"callback": "https://yourapp.com/webhooks/neutron",
"createdAt": 1747889654376
}Save the id — you need it to update or remove the webhook later.
2. Receive Events
When a transaction changes state, Neutron sends a POST request to your callback URL with the transaction details in the body. The request includes a signature header for verification.
3. Verify the Signature
Every webhook request includes a signature generated using the secret you provided when creating the webhook. Always verify this signature before processing the event.
To verify:
- Read the raw request body
- Compute HMAC-SHA256 of the body using your webhook secret
- Compare with the signature in the request header
Node.js:
const crypto = require('crypto');
function verifyWebhookSignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Python:
import hmac
import hashlib
def verify_webhook(body, signature, secret):
expected = hmac.new(
secret.encode(),
body if isinstance(body, bytes) else body.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)Security: Always use constant-time comparison (
timingSafeEqualorcompare_digest) to prevent timing attacks.
4. Respond
Return a 200 OK response promptly. If your server doesn't respond with a 2xx status code, Neutron will retry the delivery.
Webhook Events
Webhooks fire on transaction state changes. The payload includes the full transaction object with its current state. Key states to handle:
| State | Meaning | Action |
|---|---|---|
quoted | Transaction created, awaiting confirmation | Informational |
srccreated | Source side initiated | Payment is being processed |
destsent | Destination payout sent | Funds are on the way |
completed | Transaction fully completed | Mark as successful |
failed | Transaction failed | Handle the failure |
cancelled | Transaction was cancelled | Clean up |
See Transaction Status Types for the complete list.
Best Practices
Idempotency
You may receive the same event more than once (e.g., due to retries). Design your webhook handler to be idempotent — processing the same event twice should have the same result as processing it once.
Tip: Track processed transaction IDs and skip duplicates.
Quick Response
Process webhooks asynchronously. Accept the webhook immediately (return 200), then process the event in a background job. Don't do heavy work in the webhook handler — Neutron may time out waiting for your response.
Do this: Receive, queue, return 200, then process in background.
Not this: Receive, do heavy processing, then return 200 (slow, may timeout).
Error Handling
If your endpoint is temporarily unavailable, Neutron will retry delivery with exponential backoff. Make sure your endpoint can handle occasional bursts of events if it comes back online after downtime.
HTTPS Only
Always use HTTPS for your callback URL. Webhook payloads contain sensitive transaction data.
Managing Webhooks
| Action | Endpoint |
|---|---|
| Create | POST /api/v2/webhook |
| List | GET /api/v2/webhook |
| Update | PUT /api/v2/webhook/webhookId |
| Remove | DELETE /api/v2/webhook/webhookId |
You can only have one active webhook per account. To change your callback URL or secret, use the update endpoint.
