Skip to main content

Webhooks

Webhooks allow you to receive real-time notifications when events occur in NowRamp, such as order completions, KYC approvals, and wallet screenings.

Setting Up Webhooks

Via Dashboard

  1. Go to Settings > Webhooks
  2. Click Add Endpoint
  3. Enter your endpoint URL
  4. Select the events you want to receive
  5. Save and note the signing secret

Via API

curl -X POST https://api.nowramp.com/v1/webhooks \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://partner-app.com/webhooks/ramp",
    "events": ["order.completed", "kyc.approved"],
    "secret": "your_signing_secret"
  }'

Webhook Payload

All webhooks follow this structure:
{
  "id": "evt_abc123",
  "type": "order.completed",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "id": "order_xyz789",
    "customerId": "cust_abc123",
    "status": "completed",
    // Event-specific data
  }
}

Verifying Signatures

All webhooks include an HMAC signature in the X-Webhook-Signature header. Always verify this signature.

Node.js

const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express middleware
app.post('/webhooks/ramp', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const payload = req.body.toString();

  if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(payload);
  handleWebhookEvent(event);

  res.status(200).send('OK');
});

Python

import hmac
import hashlib

def verify_webhook(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

Event Types

Order Events

EventDescription
order.createdNew order created
order.processingOrder is processing
order.awaiting_paymentWaiting for payment
order.payment_receivedPayment confirmed
order.completedOrder completed
order.failedOrder failed
order.cancelledOrder cancelled
order.refundedPayment refunded

KYC Events

EventDescription
kyc.startedCustomer started KYC
kyc.approvedKYC approved
kyc.rejectedKYC rejected
kyc.expiredKYC link expired

Wallet Events

EventDescription
wallet.createdWallet added
wallet.screenedScreening completed
wallet.blockedWallet blocked
wallet.deletedWallet removed

Customer Events

EventDescription
customer.createdNew customer
customer.updatedCustomer updated

Handling Events

function handleWebhookEvent(event) {
  switch (event.type) {
    case 'order.completed':
      handleOrderCompleted(event.data);
      break;
    case 'kyc.approved':
      handleKycApproved(event.data);
      break;
    case 'wallet.blocked':
      handleWalletBlocked(event.data);
      break;
    default:
      console.log('Unhandled event type:', event.type);
  }
}

function handleOrderCompleted(order) {
  // Update your database
  db.orders.update(order.id, { status: 'completed' });

  // Notify the user
  sendNotification(order.customerId, 'Your crypto purchase is complete!');
}

Retry Policy

Failed webhook deliveries are retried with exponential backoff:
AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours
68 hours
724 hours
After 7 failed attempts, the webhook is moved to the dead-letter queue.

Dead-Letter Queue

Failed webhooks are stored in the dead-letter queue for manual review:
# View failed webhooks
curl https://api.nowramp.com/v1/webhooks/dead-letter \
  -H "X-API-Key: your_api_key"

# Retry a failed webhook
curl -X POST https://api.nowramp.com/v1/webhooks/dead-letter/evt_abc123/retry \
  -H "X-API-Key: your_api_key"

Best Practices

1. Respond Quickly

Return a 2xx response as soon as possible. Process the event asynchronously:
app.post('/webhooks/ramp', (req, res) => {
  // Respond immediately
  res.status(200).send('OK');

  // Process asynchronously
  processWebhookAsync(req.body);
});

2. Handle Duplicates

Webhooks may be delivered more than once. Use idempotency:
async function handleWebhook(event) {
  // Check if already processed
  const processed = await db.webhookEvents.findOne({ id: event.id });
  if (processed) return;

  // Process and mark as handled
  await processEvent(event);
  await db.webhookEvents.insert({ id: event.id, processedAt: new Date() });
}

3. Verify Signatures

Always verify the webhook signature before processing.

4. Use HTTPS

Webhook endpoints must use HTTPS in production.

5. Log Everything

Log webhook events for debugging:
function handleWebhook(event) {
  console.log('Webhook received:', {
    id: event.id,
    type: event.type,
    timestamp: event.timestamp,
  });
  // ...
}