Skip to main content

Prerequisites

Before setting up webhooks, ensure you have:
  • An active Affonso account with an affiliate program
  • A publicly accessible HTTPS endpoint to receive webhooks
  • The ability to verify webhook signatures (recommended)

Creating a Webhook Endpoint

1

Navigate to Webhooks

Go to your Affonso dashboard and select SettingsWebhooks from the sidebar.
2

Add New Endpoint

Click Add Endpoint and enter your webhook URL:
https://your-app.com/api/webhooks/affonso
Your endpoint must use HTTPS. HTTP endpoints are not supported for security reasons.
3

Select Events

Choose which events you want to receive. You can select:
  • All events - Receive every webhook event
  • Specific events - Only receive selected event types
Start with specific events you need. You can always add more later.
4

Copy Signing Secret

After creating the endpoint, copy your Signing Secret. You’ll need this to verify webhook signatures.
whsec_abc123xyz...
Store this secret securely. It’s only shown once!

Verifying Webhook Signatures

Always verify webhook signatures to ensure requests are from Affonso.

Signature Header

Each webhook request includes a signature header:
X-Affonso-Signature: t=1704067200,v1=abc123...
The header contains:
  • t - Unix timestamp of when the signature was generated
  • v1 - The HMAC-SHA256 signature

Verification Process

import crypto from 'crypto';

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const [timestampPart, signaturePart] = signature.split(',');
  const timestamp = timestampPart.replace('t=', '');
  const expectedSignature = signaturePart.replace('v1=', '');
  
  // Check timestamp is within 5 minutes
  const currentTime = Math.floor(Date.now() / 1000);
  if (Math.abs(currentTime - parseInt(timestamp)) > 300) {
    return false;
  }
  
  // Compute expected signature
  const signedPayload = `${timestamp}.${payload}`;
  const computedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature),
    Buffer.from(computedSignature)
  );
}

Responding to Webhooks

Your endpoint must respond correctly for webhooks to be considered delivered.

Success Response

Return a 2xx status code to acknowledge receipt:
{
  "received": true
}

Response Time

Your endpoint should respond within 30 seconds. If processing takes longer:
  1. Acknowledge the webhook immediately
  2. Process the event asynchronously
  3. Use a job queue for heavy processing
// Good: Acknowledge immediately, process async
app.post('/webhooks/affonso', async (req, res) => {
  // Verify signature first
  if (!verifySignature(req)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Acknowledge immediately
  res.status(200).json({ received: true });
  
  // Process asynchronously
  await queue.add('process-webhook', req.body);
});

Testing Webhooks

Test Events

Use the Send Test Event button in your dashboard to send a test webhook to your endpoint.

Local Development

For local development, use a tunneling service:
ngrok http 3000
# Use the HTTPS URL as your webhook endpoint

Troubleshooting

  • Verify your endpoint URL is correct and publicly accessible
  • Check that your endpoint returns a 2xx status code
  • Ensure you’ve selected the correct events to receive
  • Ensure you’re using the raw request body, not parsed JSON
  • Check that your signing secret is correct
  • Verify the timestamp is within 5 minutes
  • Implement idempotency using the event id field
  • Store processed event IDs and skip duplicates