Skip to main content

Getting Started

To start receiving webhooks from Rove, you’ll need to configure a webhook endpoint in your Rove partner settings.
  1. Provide Your Endpoint URL: This is the HTTP/HTTPS URL on your server where Rove will send POST requests for event notifications.
  2. Select Event Types: Choose the specific events you want to be notified about (e.g., transfer-in.success, transfer-in.failed).
  3. Set Up Your Webhook Secret: You can configure your webhook subscription and put your own shared_secret in the Rove admin dashboard. This secret is crucial for verifying that incoming webhooks are genuinely from Rove and have not been tampered with. Keep this secret confidential.
Currently, the setup of webhook subscriptions (URL, event names, and secret) is managed through your Rove Developer Admin Panel interface.

Available Events

Rove currently supports the following webhook events:
Event NameDescription
transfer-in.successFired when an inbound transfer has successfully completed.
transfer-in.failedFired when an inbound transfer has failed.
We are continuously working on adding more event types.

Payload Structure

When an event you’ve subscribed to occurs, Rove will send an HTTP POST request to your configured endpoint URL. The request body will be a JSON object with the following structure:
{
  "event_name": "event_type_string",
  "payload": {
    // Event-specific payload
  }
}
event_name: (String) The name of the event that triggered the webhook (e.g., transfer-in.success). payload: (Object) An object containing detailed information about the event. Example: TransferInPayload For transfer-in.success and transfer-in.failed events, the nested payload object will have the following structure:
type TransferInPayload = {
  transaction_id: string;  // Unique identifier for the transaction (uuid)
  account_id: string;      // Identifier for the associated account (uuid)
  amount: number;          // The transaction amount (in miles) (integer)
  created_at: string;      // ISO 8601 timestamp of when the transaction was created
  status: 'success' | 'failed' | 'pending'; // Current status of the transaction
  reference_id: string;    // A client-provided reference ID for the transaction
}
Example Webhook Body for transfer-in.success or transfer-in.failed:
{
  "event_name": "transfer-in.success" | "transfer-in.failed",
  "payload": {
    "transaction_id": "txn_123abc456def",
    "account_id": "acc_789ghi012jkl",
    "amount": 100,
    "created_at": "2024-05-23T10:30:00Z",
    "status": "success" | "failed",
    "reference_id": "your_reference_id"
  }
}

Verifying Signatures (Security)

To ensure the integrity and authenticity of the webhooks you receive, Rove includes a signature in the x-signature HTTP header of each request. This signature is an HMAC-SHA256 hash of the raw request body, generated using your unique payload_secret. You must verify this signature on your end before processing the webhook. Steps to Verify the Signature:
  1. Extract the Signature: Get the value of the x-signature header from the incoming request.
  2. Create an HMAC-SHA256 hash using your payload_secret as the key and the raw request body string as the message.
  3. Encode the resulting hash in Base64.
  4. Compare Signatures: Compare the signature you calculated with the signature received in the x-signature header. They must be identical.
Crucial: Always use the raw request body for signature calculation. Parsing and re-serializing the JSON can alter its structure (e.g., whitespace, key order) and result in a signature mismatch.

Example: Verifying Signature in Node.js

Here’s how you might verify the signature on your server if you’re using Node.js:
const crypto = require('node:crypto');

function verifyWebhookSignature(rawBody, receivedSignature, webhookSecret) {
  // rawBody should be the raw string body of the request
  // receivedSignature is the value from the 'x-signature' header
  // webhookSecret is your Rove payload_secret

  // 1. Parse the raw body if it's a string, or use as is if it's already an object
  // If rawBody is a string, use it directly; otherwise stringify the object
  const bodyString = typeof rawBody === 'string' ? rawBody : JSON.stringify(rawBody);

  // 2. Create an HMAC-SHA256 hash using the webhook secret
  const hmac = crypto.createHmac('sha256', webhookSecret);
  hmac.update(bodyString);

  // 3. Calculate the Base64-encoded digest
  const signature = hmac.digest('base64');

  // 4. Compare with the signature in the request header
  return signature === receivedSignature;
}

Example usage within an Express.js route:

Make sure to use a body parser that preserves the raw body,
or access the raw body before it’s parsed.
app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf.toString(); } }));

app.post('/your-webhook-endpoint', (req, res) => {
  const signature = req.headers['x-signature'];
  const rawBody = req.rawBody; // Assuming rawBody is available
  const WEBHOOK_SECRET = 'your_rove_payload_secret_here';

  if (!signature) {
    return res.status(400).send('Missing signature.');
  }

  if (verifyWebhookSignature(rawBody, signature, WEBHOOK_SECRET)) {
    console.log('Signature verified successfully!');
    const eventData = JSON.parse(rawBody);
    // Process the eventData.payload
    // ...
    res.status(200).send('Webhook received');
  } else {
    console.error('Signature verification failed!');
    res.status(403).send('Invalid signature.');
  }
});

Responding to Webhooks

Your endpoint should respond to webhook requests promptly. Acknowledge with 2xx: Return a 200 OK (or any 2xx) HTTP status code as quickly as possible to indicate successful receipt. Rove considers any other status code (or a timeout) as a delivery failure.

Error Handling & Retries

Rove’s webhook system logs the outcome of each delivery attempt, including the response status code and body received from your endpoint.
  • Delivery Failures: If Rove does not receive a 2xx response from your endpoint (e.g., due to network errors, your server returning a 4xx or 5xx error, or a timeout), the delivery will be marked as failed in our logs.