Outgoing webhooks send HTTP POST requests to your server when specific events occur in your Partnero program.
How It Works
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Event │ │ Partnero │ │ Your Server │
│ Occurs │────▶│ Webhook │────▶│ Endpoint │
│ │ │ System │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
POST /your-webhook
{event, data, timestamp}
Setting Up Outgoing Webhooks
Create your endpoint
Create an HTTPS endpoint on your server to receive webhook events:// Express.js example
app.post('/webhooks/partnero', (req, res) => {
const { event, data, timestamp } = req.body;
// Process the event
console.log(`Received ${event} event`);
// Respond quickly with 200
res.status(200).send('OK');
// Process asynchronously if needed
processWebhookAsync(event, data);
});
Register in Partnero
- Go to Program Settings → Webhooks
- Click Add Webhook
- Enter your endpoint URL
- Select which events to receive
- Save and copy the signing secret
Verify signatures
Verify webhook signatures to ensure requests are from Partnero:const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
app.post('/webhooks/partnero', (req, res) => {
const signature = req.headers['x-partnero-signature'];
if (!verifyWebhookSignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process verified webhook
res.status(200).send('OK');
});
Available Events
Partner Events
| Event | Description |
|---|
partner.created | New partner signs up or is created |
partner.updated | Partner information is updated |
partner.approved | Partner application is approved |
partner.rejected | Partner application is rejected |
partner.archived | Partner is archived |
partner.deleted | Partner is deleted |
Customer Events
| Event | Description |
|---|
customer.created | New customer is created |
customer.updated | Customer information is updated |
customer.deleted | Customer is deleted |
Transaction Events
| Event | Description |
|---|
transaction.created | New transaction is recorded |
transaction.updated | Transaction is updated |
transaction.deleted | Transaction is deleted (refund) |
Reward Events
| Event | Description |
|---|
reward.created | Commission/reward is created |
reward.approved | Reward is approved for payout |
reward.paid | Reward is marked as paid |
Webhook Payload
All webhooks follow this structure:
{
"event": "partner.created",
"data": {
"id": "partner_abc123",
"email": "[email protected]",
"name": "John",
"surname": "Doe",
"status": "approved",
"created_at": "2025-01-15T10:30:00.000000Z",
"metadata": {}
},
"program_id": "PROG123",
"timestamp": "2025-01-15T10:30:00.000000Z"
}
Event-Specific Payloads
{
"event": "partner.created",
"data": {
"id": "partner_abc123",
"key": "john-doe",
"email": "[email protected]",
"name": "John",
"surname": "Doe",
"status": "pending",
"referral_link": "https://yoursite.com?ref=john-doe",
"created_at": "2025-01-15T10:30:00.000000Z"
}
}
{
"event": "transaction.created",
"data": {
"key": "txn_123",
"amount": 99.99,
"currency": "USD",
"action": "sale",
"customer": {
"id": "cust_456",
"email": "[email protected]"
},
"partner": {
"id": "partner_abc123",
"email": "[email protected]"
},
"reward": {
"amount": 19.99,
"currency": "USD"
},
"created_at": "2025-01-15T14:22:00.000000Z"
}
}
{
"event": "reward.approved",
"data": {
"id": "reward_789",
"amount": 19.99,
"currency": "USD",
"partner": {
"id": "partner_abc123",
"email": "[email protected]"
},
"transaction_key": "txn_123",
"approved_at": "2025-01-20T09:00:00.000000Z"
}
}
Handling Webhooks
Best Practices
Respond Quickly
Return a 2xx status within 5 seconds. Process data asynchronously.
Implement Idempotency
Handle duplicate deliveries by tracking processed event IDs.
Use HTTPS
Always use HTTPS endpoints in production.
Log Everything
Log all received webhooks for debugging and audit trails.
Handling Retries
Partnero retries failed webhooks with exponential backoff:
| Attempt | Delay |
|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
After 5 failed attempts, the webhook is marked as failed. Check your webhook logs in the Partnero dashboard.
Example: Processing Partner Signup
app.post('/webhooks/partnero', async (req, res) => {
const { event, data } = req.body;
// Respond immediately
res.status(200).send('OK');
// Process asynchronously
switch (event) {
case 'partner.created':
await sendWelcomeEmail(data.email, data.name);
await addToMailingList(data.email);
await notifySlack(`New partner: ${data.name} (${data.email})`);
break;
case 'transaction.created':
await updateCRM(data);
await syncToAccounting(data);
break;
case 'reward.approved':
await schedulePayoutReminder(data);
break;
}
});
Testing Webhooks
Using the Dashboard
- Go to Program Settings → Webhooks
- Find your webhook and click Test
- Select an event type
- Click Send Test Webhook
Using ngrok for Local Development
# Start ngrok tunnel
ngrok http 3000
# Use the ngrok URL as your webhook endpoint
# https://abc123.ngrok.io/webhooks/partnero
Troubleshooting
- Verify your endpoint URL is correct and accessible
- Check your server logs for incoming requests
- Ensure your firewall allows requests from Partnero IPs
- Check the webhook logs in your Partnero dashboard
Signature verification failing
- Ensure you’re using the correct signing secret
- Verify you’re hashing the raw request body
- Check for any middleware modifying the request body
Duplicate webhooks received
- Implement idempotency using event IDs
- Track processed webhooks in your database
- Return 200 status quickly to prevent retries
API Reference
For programmatic webhook management, see the Webhooks API.