Skip to main content
Webhooks allow you to receive real-time notifications when events occur in your Rinne account. Instead of polling the API, Rinne sends HTTP POST requests to your server when important events happen.

Webhook events

Rinne sends webhooks for the following events:

Transaction events

  • transaction.created: New transaction created
  • transaction.status-changed: Transaction status updated

Affiliation events

  • affiliation.created: New affiliation created
  • affiliation.status-changed: Affiliation status updated

Company events

  • company.created: New company created
  • company.status-changed: Company status updated

Banking events

  • cashout.created: New cashout request created
  • cashout.status-changed: Cashout status updated
  • internal-transfer.created: New internal transfer created
  • internal-transfer.status-changed: Internal transfer status updated

Webhook payload structure

All webhooks follow a consistent structure:
{
  "id": "evt_123456789",
  "type": "transaction.status-changed",
  "version": 1,
  "timestamp": "2025-01-21T10:30:00.000Z",
  "source": "transaction-service",
  "company_id": "company-123",
  "correlation_id": "corr-987654321",
  "payload": {
    "transaction_id": "tx_123456789",
    "old_status": "WAITING_PAYMENT",
    "new_status": "APPROVED"
  }
}

Common fields

  • id: Unique event identifier
  • type: Event type (e.g., transaction.status-changed)
  • version: Event schema version
  • timestamp: When the event occurred (ISO 8601)
  • source: Service that generated the event
  • company_id: Company associated with the event
  • correlation_id: ID for tracking related events
  • payload: Event-specific data

Setting up webhooks

Contact Rinne support to configure your webhook endpoint URL. We’ll create a webhook configuration for your organization.

Webhook endpoint requirements

Your endpoint must:
  • Accept POST requests
  • Respond with 2xx status code within 5 seconds
  • Use HTTPS (required for production)
  • Handle duplicate events (idempotency)

Webhook security

Rinne uses Svix for webhook delivery, which provides:
  • Request signing for verification
  • Automatic retries with exponential backoff
  • Webhook dashboard for monitoring
  • Replay functionality for testing

Verifying webhook signatures

Verify that webhooks are from Rinne by checking the signature:
const svix = require('svix');

app.post('/webhooks/rinne', (req, res) => {
  const payload = req.body;
  const headers = req.headers;
  
  const wh = new svix.Webhook(WEBHOOK_SECRET);
  
  try {
    const verified = wh.verify(payload, headers);
    // Process the webhook
    res.status(200).send('OK');
  } catch (err) {
    res.status(400).send('Invalid signature');
  }
});

Handling webhook events

Transaction status changed

if (event.type === 'transaction.status-changed') {
  const { transaction_id, old_status, new_status } = event.payload;
  
  if (new_status === 'APPROVED') {
    // Payment approved - fulfill order
    await fulfillOrder(transaction_id);
  } else if (new_status === 'REFUSED') {
    // Payment declined - notify customer
    await notifyPaymentFailed(transaction_id);
  }
}

Affiliation status changed

if (event.type === 'affiliation.status-changed') {
  const { affiliation_id, new_status, onboarding_url } = event.payload;
  
  if (new_status === 'ACTIVE') {
    // Affiliation activated - merchant can process transactions
    await enableMerchantPayments(affiliation_id);
  } else if (new_status === 'WAITING_DOCUMENTS') {
    // Provider needs documents - send onboarding URL to merchant
    await sendOnboardingLink(affiliation_id, onboarding_url);
  }
}

Webhook dashboard

Access your webhook dashboard to:
  • View webhook delivery history
  • Replay failed webhooks
  • Test webhook endpoints
  • Monitor delivery success rates
Get your dashboard URL:
curl https://api-sandbox.rinne.com.br/core/v1/webhooks/dashboard \
  -H "x-api-key: YOUR_API_KEY"

Retry behavior

If your endpoint returns an error or times out, Rinne automatically retries:
  • Immediate retry
  • After 5 seconds
  • After 5 minutes
  • After 30 minutes
  • After 2 hours
  • After 5 hours
  • After 10 hours
  • After 24 hours
After all retries fail, the webhook is marked as failed in your dashboard.

Best practices

Return a 200 status code immediately, then process the webhook asynchronously. Don’t perform long-running operations in the webhook handler.
Use the event id to track processed events and ignore duplicates. Webhooks may be delivered more than once.
Always verify webhook signatures to ensure requests are from Rinne.
Use correlation_id to track related events across different webhook types.
Regularly check your webhook dashboard for failed deliveries and fix issues promptly.

Testing webhooks

Local testing with ngrok

Use ngrok to expose your local server for webhook testing:
ngrok http 3000
Provide the ngrok URL to Rinne support for webhook configuration.

Webhook replay

Use the webhook dashboard to replay events to your endpoint for testing.

Example webhook handler

const express = require('express');
const { Webhook } = require('svix');

const app = express();
app.use(express.json());

app.post('/webhooks/rinne', async (req, res) => {
  const payload = JSON.stringify(req.body);
  const headers = req.headers;
  
  const wh = new Webhook(process.env.WEBHOOK_SECRET);
  
  let event;
  try {
    event = wh.verify(payload, headers);
  } catch (err) {
    return res.status(400).send('Invalid signature');
  }
  
  // Respond immediately
  res.status(200).send('OK');
  
  // Process asynchronously
  processWebhook(event).catch(console.error);
});

async function processWebhook(event) {
  switch (event.type) {
    case 'transaction.status-changed':
      await handleTransactionStatusChanged(event.payload);
      break;
    case 'affiliation.status-changed':
      await handleAffiliationStatusChanged(event.payload);
      break;
    // Handle other event types
  }
}

app.listen(3000);

Next steps