> ## Documentation Index
> Fetch the complete documentation index at: https://docs.partnero.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Outgoing webhooks

> Receive real-time notifications when events occur in Partnero

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

<Steps>
  <Step title="Create your endpoint">
    Create an HTTPS endpoint on your server to receive webhook events:

    ```javascript theme={null}
    // 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);
    });
    ```
  </Step>

  <Step title="Register in Partnero">
    1. Go to **Program Settings → Webhooks**
    2. Click **Add Webhook**
    3. Enter your endpoint URL
    4. Select which events to receive
    5. Save and copy the signing secret
  </Step>

  <Step title="Verify signatures">
    Verify webhook signatures to ensure requests are from Partnero:

    ```javascript theme={null}
    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');
    });
    ```
  </Step>
</Steps>

## 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:

```json theme={null}
{
  "event": "partner.created",
  "data": {
    "id": "partner_abc123",
    "email": "partner@partnero.com",
    "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

<AccordionGroup>
  <Accordion title="partner.created">
    ```json theme={null}
    {
      "event": "partner.created",
      "data": {
        "id": "partner_abc123",
        "key": "john-doe",
        "email": "partner@partnero.com",
        "name": "John",
        "surname": "Doe",
        "status": "pending",
        "referral_link": "https://yoursite.com?ref=john-doe",
        "created_at": "2025-01-15T10:30:00.000000Z"
      }
    }
    ```
  </Accordion>

  <Accordion title="transaction.created">
    ```json theme={null}
    {
      "event": "transaction.created",
      "data": {
        "key": "txn_123",
        "amount": 99.99,
        "currency": "USD",
        "action": "sale",
        "customer": {
          "id": "cust_456",
          "email": "customer@partnero.com"
        },
        "partner": {
          "id": "partner_abc123",
          "email": "partner@partnero.com"
        },
        "reward": {
          "amount": 19.99,
          "currency": "USD"
        },
        "created_at": "2025-01-15T14:22:00.000000Z"
      }
    }
    ```
  </Accordion>

  <Accordion title="reward.approved">
    ```json theme={null}
    {
      "event": "reward.approved",
      "data": {
        "id": "reward_789",
        "amount": 19.99,
        "currency": "USD",
        "partner": {
          "id": "partner_abc123",
          "email": "partner@partnero.com"
        },
        "transaction_key": "txn_123",
        "approved_at": "2025-01-20T09:00:00.000000Z"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

## Handling Webhooks

### Best Practices

<CardGroup cols={2}>
  <Card title="Respond Quickly" icon="bolt">
    Return a 2xx status within 5 seconds. Process data asynchronously.
  </Card>

  <Card title="Implement Idempotency" icon="shield-check">
    Handle duplicate deliveries by tracking processed event IDs.
  </Card>

  <Card title="Use HTTPS" icon="lock">
    Always use HTTPS endpoints in production.
  </Card>

  <Card title="Log Everything" icon="file-lines">
    Log all received webhooks for debugging and audit trails.
  </Card>
</CardGroup>

### 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    |

<Note>
  After 5 failed attempts, the webhook is marked as failed. Check your webhook logs in the Partnero dashboard.
</Note>

### Example: Processing Partner Signup

```javascript theme={null}
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

1. Go to **Program Settings → Webhooks**
2. Find your webhook and click **Test**
3. Select an event type
4. Click **Send Test Webhook**

### Using ngrok for Local Development

```bash theme={null}
# Start ngrok tunnel
ngrok http 3000

# Use the ngrok URL as your webhook endpoint
# https://abc123.ngrok.io/webhooks/partnero
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Webhooks not arriving">
    * 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
  </Accordion>

  <Accordion title="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
  </Accordion>

  <Accordion title="Duplicate webhooks received">
    * Implement idempotency using event IDs
    * Track processed webhooks in your database
    * Return 200 status quickly to prevent retries
  </Accordion>
</AccordionGroup>

## API Reference

For programmatic webhook management, see the [Webhooks API](/api-reference/webhooks/overview).
