NodeRailsCRYPTO PAYMENT INFRASTRUCTURE
DocumentationAPI Reference
Dashboard

Webhooks

Receive real-time notifications when events happen in your NodeRails account: payments captured, invoices paid, subscriptions created, and more.

How webhooks work

  1. You register a webhook endpoint URL and choose which events to listen to.
  2. When an event occurs, NodeRails sends an HTTP POST to your endpoint with a JSON payload.
  3. Your server verifies the signature, processes the event, and responds with 2xx.
  4. If delivery fails, NodeRails retries with exponential backoff.

Supported events

EventDescription
payment_intent.createdA payment intent was created
payment_intent.authorizedCustomer gave approval to pull money from their wallet
payment_intent.capturedFunds taken from wallet, locked in escrow, and confirmed on-chain
payment_intent.settledEscrowed payment settled to merchant
payment_intent.cancelledPayment intent was cancelled
payment_intent.refundedPayment was refunded
payment_intent.failedPayment attempt failed
checkout_session.completedCheckout session completed
checkout_session.expiredCheckout session expired
invoice.paidInvoice was paid
invoice.voidedInvoice was voided
subscription.createdA subscription was created
subscription.pausedSubscription was paused
subscription.resumedSubscription was resumed
subscription.cancelledSubscription was cancelled
subscription.renewedSubscription period renewed

Webhook payload

Every webhook delivery sends a JSON object with the following structure:

Webhook payloadjson
{
  "id": "evt_abc123",
  "type": "payment_intent.captured",
  "data": {
    "id": "pi_xyz789",
    "status": "CAPTURED",
    "amount": "99.99",
    "currency": "USD",
    "chainId": 1,
    "tokenAddress": "0x...",
    "txHash": "0x...",
    ...
  },
  "createdAt": "2025-01-15T10:30:00.000Z"
}

Signature verification

Every webhook request includes a signature header so you can verify the payload originated from NodeRails and wasn't tampered with.

HeaderDescription
x-noderails-signatureHMAC-SHA256 hex digest of the raw body
x-noderails-timestampUnix timestamp (ms) when the payload was signed

Using the SDK

The easiest way to verify signatures is with the SDK's webhooks helper:

Express webhook handlertypescript
import express from 'express';
import { NodeRails } from '@noderails/sdk';

const app = express();
const noderails = new NodeRails({
  appId: 'your-app-id',
  apiKey: 'nr_live_sk_...',
});

const WEBHOOK_SECRET = 'whsec_...'; // From your dashboard

// Important: use raw body for signature verification
app.post(
  '/webhooks/noderails',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const signature = req.headers['x-noderails-signature'] as string;

    try {
      const event = noderails.webhooks.constructEvent(
        req.body,         // Raw body (Buffer or string)
        signature,        // Signature header value
        WEBHOOK_SECRET,   // Your webhook signing secret
      );

      // Handle the event
      switch (event.type) {
        case 'payment_intent.captured':
          console.log('Payment captured:', event.data.id);
          break;
        case 'invoice.paid':
          console.log('Invoice paid:', event.data.id);
          break;
        default:
          console.log('Unhandled event:', event.type);
      }

      res.json({ received: true });
    } catch (err) {
      console.error('Webhook signature verification failed:', err);
      res.status(400).send('Invalid signature');
    }
  }
);

Manual verification

If you're not using the SDK, you can verify the HMAC-SHA256 signature manually:

Manual HMAC verificationtypescript
import crypto from 'crypto';

function verifyWebhook(
  rawBody: string | Buffer,
  signature: string,
  secret: string,
): boolean {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected),
  );
}
⚠️

Use the raw body

Always use the raw, unparsed request body for signature verification. Parsing JSON and re-stringifying can change whitespace or key order, causing the signature check to fail.

Retry behavior

If your endpoint returns a non-2xx status code or doesn't respond within 15 seconds, NodeRails will retry the delivery:

  • Up to 5 retries with exponential backoff
  • Retry delays: 1 min, 5 min, 30 min, 2 hours, 24 hours
  • After all retries are exhausted, the delivery is marked as failed

Best practices

  • Return 2xx quickly. Process events asynchronously using a queue. Acknowledge receipt immediately to avoid timeouts and retries.
  • Handle duplicates. Use the event id field to deduplicate. The same event may be delivered more than once during retries.
  • Verify signatures. Always verify the webhook signature before processing. Never trust unverified payloads.
  • Use HTTPS. Webhook endpoints must use HTTPS in production for security.

Testing webhooks

You can send a test ping from the dashboard or via the API to verify your endpoint is reachable:

Send a test pingtypescript
// Via SDK
await noderails.webhookEndpoints.testPing('webhook-endpoint-id');

You can also view recent deliveries and their status in the dashboard or via the API:

List deliveriestypescript
const deliveries = await noderails.webhookEndpoints.listDeliveries(
  'webhook-endpoint-id',
  { limit: 20 }
);

for (const delivery of deliveries.data) {
  console.log(delivery.status, delivery.responseCode);
}