Node.js SDK
The official XRNotify Node.js SDK provides a typed, promise-based interface for managing webhooks, querying deliveries, and verifying webhook signatures. Supports both CommonJS and ESM. Requires Node.js 18 or later.
Installation
npm install @xrnotify/sdk # or yarn add @xrnotify/sdk # or pnpm add @xrnotify/sdk
Initialization
Create a client instance with your API key. Store the key in an environment variable — never hard-code it.
import { XRNotify } from '@xrnotify/sdk';
const client = new XRNotify({
apiKey: process.env.XRNOTIFY_API_KEY!,
// Optional: use test environment for development
// environment: 'test'
});Test environment: Set environment: 'test' to use test API keys (xrn_test_...). Test mode delivers synthetic events only — no real XRPL data is consumed.
Creating a webhook
Register a new webhook endpoint. The response includes a secret field that is only returned once — store it securely in your secrets manager.
const webhook = await client.webhooks.create({
url: 'https://yourapp.com/webhooks/xrpl',
eventTypes: ['payment.xrp', 'nft.minted'],
accountFilters: ['rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe'],
description: 'Payment processor'
});
console.log(webhook.id); // wh_abc123
console.log(webhook.secret); // Only available on creation — store immediatelyImportant: The secret field is only present in the creation response. It cannot be retrieved again. If lost, delete and recreate the webhook.
Listing webhooks
Retrieve a paginated list of webhooks in your account. Use hasMore and the last item's ID to paginate through results.
const { data, hasMore } = await client.webhooks.list({ limit: 10 });
for (const webhook of data) {
console.log(webhook.id, webhook.url, webhook.isActive);
}
// Fetch the next page
if (hasMore) {
const nextPage = await client.webhooks.list({
limit: 10,
startingAfter: data[data.length - 1].id
});
}Updating a webhook
Update any field of an existing webhook. Only the fields you provide are changed — unspecified fields retain their current values.
// Pause a webhook
await client.webhooks.update('wh_abc123', {
isActive: false
});
// Change subscribed events
await client.webhooks.update('wh_abc123', {
eventTypes: ['payment.xrp', 'payment.issued', 'nft.*']
});
// Update both URL and filters
await client.webhooks.update('wh_abc123', {
url: 'https://newapp.com/webhooks/xrpl',
accountFilters: ['rN7n3473SaZBCG4dFL83w7PB2bBdDiAkzN']
});Listing deliveries
Query delivery history for a webhook, filtered by status and time range. Useful for debugging failed deliveries.
const { data } = await client.deliveries.list({
webhookId: 'wh_abc123',
status: 'failed',
since: new Date('2024-01-01')
});
for (const delivery of data) {
console.log(
delivery.id,
delivery.eventType,
delivery.statusCode,
delivery.lastError
);
}Verifying signatures
Always verify the X-XRNotify-Signature header before processing an incoming webhook. The SDK provides a verifySignature helper that uses a constant-time comparison to prevent timing attacks.
import { verifySignature } from '@xrnotify/sdk';
import express from 'express';
const app = express();
// Use express.raw() — NOT express.json() — to get the raw body buffer
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const isValid = verifySignature({
payload: req.body,
signature: req.headers['x-xrnotify-signature'] as string,
secret: process.env.WEBHOOK_SECRET!
});
if (!isValid) {
return res.status(401).send('Unauthorized');
}
const event = JSON.parse(req.body);
switch (event.event_type) {
case 'payment.xrp':
console.log('XRP payment:', event.payload.amount_xrp, 'XRP');
break;
case 'nft.minted':
console.log('NFT minted:', event.payload.nft_id);
break;
}
res.sendStatus(200);
});Raw body required: Signature verification operates on the raw bytes of the request body. Parsing JSON before calling verifySignature will corrupt the comparison and cause all signatures to fail.
TypeScript types
The SDK exports full TypeScript types for all events and payloads. Use these to write type-safe event handlers.
import type {
WebhookEvent,
PaymentXrpPayload,
PaymentIssuedPayload,
NftMintedPayload,
NftOfferAcceptedPayload,
DexOfferFilledPayload,
TrustlineCreatedPayload
} from '@xrnotify/sdk';
function handleEvent(event: WebhookEvent): void {
if (event.event_type === 'payment.xrp') {
const payload = event.payload as PaymentXrpPayload;
console.log(`${payload.amount_xrp} XRP from ${payload.sender} to ${payload.receiver}`);
}
if (event.event_type === 'nft.minted') {
const payload = event.payload as NftMintedPayload;
console.log('New NFT:', payload.nft_id, 'URI:', payload.uri_decoded);
}
}