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

# Webhook Implementation

> Handle usmewe events in real-time

# Webhook Implementation

Receive real-time notifications when events occur in usmewe.

## Overview

Webhooks allow your application to react to events as they happen:

* Loan funded/repaid
* Vault deposits/withdrawals
* Trust Score changes
* Social Vault alerts

## Setting Up Webhooks

### 1. Create an Endpoint

Create an HTTPS endpoint to receive webhook events:

```typescript theme={null}
// Express.js example
import express from 'express';

const app = express();

app.post('/webhooks/usmewe', express.json(), (req, res) => {
  const event = req.body;

  console.log('Received event:', event.type);

  // Process the event
  handleEvent(event);

  // Respond quickly
  res.status(200).send('OK');
});

app.listen(3000);
```

### 2. Register the Webhook

Register your endpoint via API:

```bash theme={null}
curl -X POST "https://api.usmewe.com/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/usmewe",
    "events": ["loan.funded", "loan.repaid", "trust_score.updated"],
    "secret": "your_webhook_secret_here"
  }'
```

### 3. Verify Signatures

Always verify webhook signatures:

```typescript theme={null}
import crypto from 'crypto';

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  const signatureBuffer = Buffer.from(signature.replace('sha256=', ''));
  const expectedBuffer = Buffer.from(expectedSignature);

  return crypto.timingSafeEqual(signatureBuffer, expectedBuffer);
}

// In your webhook handler
app.post('/webhooks/usmewe', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-usmewe-signature'] as string;
  const payload = req.body.toString();

  if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
    console.error('Invalid webhook signature');
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(payload);
  handleEvent(event);

  res.status(200).send('OK');
});
```

## Event Structure

All webhook events follow this structure:

```json theme={null}
{
  "id": "evt_abc123xyz",
  "type": "loan.funded",
  "timestamp": "2024-01-15T12:00:00Z",
  "data": {
    // Event-specific data
  }
}
```

## Available Events

### Loan Events

#### loan.created

```json theme={null}
{
  "type": "loan.created",
  "data": {
    "loanId": "loan_xyz789",
    "userId": "user_abc123",
    "amount": "50.00",
    "duration": 14,
    "status": "pending"
  }
}
```

#### loan.funded

```json theme={null}
{
  "type": "loan.funded",
  "data": {
    "loanId": "loan_xyz789",
    "userId": "user_abc123",
    "amount": "50.00",
    "netAmount": "45.00",
    "txHash": "0x...",
    "dueDate": "2024-01-29T12:00:00Z"
  }
}
```

#### loan.repaid

```json theme={null}
{
  "type": "loan.repaid",
  "data": {
    "loanId": "loan_xyz789",
    "userId": "user_abc123",
    "amountPaid": "51.35",
    "txHash": "0x...",
    "trustScoreChange": 2
  }
}
```

#### loan.overdue

```json theme={null}
{
  "type": "loan.overdue",
  "data": {
    "loanId": "loan_xyz789",
    "userId": "user_abc123",
    "daysOverdue": 1,
    "amountDue": "51.35"
  }
}
```

### Vault Events

#### vault.deposit

```json theme={null}
{
  "type": "vault.deposit",
  "data": {
    "userId": "user_abc123",
    "usdcAmount": "1000.00",
    "tmUSDCReceived": "975.61",
    "txHash": "0x..."
  }
}
```

#### vault.withdraw

```json theme={null}
{
  "type": "vault.withdraw",
  "data": {
    "userId": "user_abc123",
    "tmUSDCRedeemed": "500.00",
    "usdcReceived": "512.50",
    "txHash": "0x..."
  }
}
```

### Trust Score Events

#### trust\_score.updated

```json theme={null}
{
  "type": "trust_score.updated",
  "data": {
    "userId": "user_abc123",
    "previousScore": 54,
    "newScore": 56,
    "change": 2,
    "reason": "on_time_repayment"
  }
}
```

### Social Vault Events

#### social\_vault.withdrawal\_requested

```json theme={null}
{
  "type": "social_vault.withdrawal_requested",
  "data": {
    "vaultOwner": "user_abc123",
    "withdrawalId": "wd_abc123",
    "amount": "500.00",
    "recipient": "0x...",
    "requiredApprovals": 2
  }
}
```

#### social\_vault.locked

```json theme={null}
{
  "type": "social_vault.locked",
  "data": {
    "vaultOwner": "user_abc123",
    "lockedAt": "2024-01-15T12:00:00Z",
    "reason": "duress_pin"
  }
}
```

## Event Handling

### Recommended Pattern

```typescript theme={null}
async function handleEvent(event: WebhookEvent) {
  // Idempotency check
  if (await isEventProcessed(event.id)) {
    console.log('Event already processed:', event.id);
    return;
  }

  switch (event.type) {
    case 'loan.funded':
      await handleLoanFunded(event.data);
      break;

    case 'loan.repaid':
      await handleLoanRepaid(event.data);
      break;

    case 'trust_score.updated':
      await handleTrustScoreUpdated(event.data);
      break;

    case 'social_vault.locked':
      await handleVaultLocked(event.data);
      break;

    default:
      console.log('Unhandled event type:', event.type);
  }

  // Mark as processed
  await markEventProcessed(event.id);
}

async function handleLoanFunded(data: LoanFundedData) {
  // Update your database
  await db.loans.update({
    where: { externalId: data.loanId },
    data: {
      status: 'funded',
      fundedAt: new Date(),
      txHash: data.txHash
    }
  });

  // Notify the user
  await sendNotification(data.userId, {
    title: 'Loan Funded!',
    body: `Your loan of ${data.netAmount} USDC has been funded.`
  });
}
```

## Error Handling

### Retry Logic

We retry failed webhooks with exponential backoff:

| Attempt | Delay      |
| ------- | ---------- |
| 1       | Immediate  |
| 2       | 1 minute   |
| 3       | 5 minutes  |
| 4       | 30 minutes |
| 5       | 2 hours    |
| 6       | 24 hours   |

### Handling Failures

```typescript theme={null}
app.post('/webhooks/usmewe', async (req, res) => {
  try {
    // Verify signature
    if (!verifySignature(req)) {
      return res.status(401).send('Invalid signature');
    }

    // Process event
    await handleEvent(req.body);

    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook processing error:', error);

    // Return 500 to trigger retry
    res.status(500).send('Processing failed');
  }
});
```

## Testing Webhooks

### Send Test Event

```bash theme={null}
curl -X POST "https://api.usmewe.com/v1/webhooks/{webhookId}/test" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"event": "loan.funded"}'
```

### Local Development

Use ngrok or similar for local testing:

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

# Update webhook URL
curl -X PATCH "https://api.usmewe.com/v1/webhooks/{webhookId}" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"url": "https://abc123.ngrok.io/webhooks/usmewe"}'
```

## Best Practices

<AccordionGroup>
  <Accordion title="Respond Quickly" icon="bolt">
    Return 200 OK within 5 seconds. Process asynchronously:

    ```typescript theme={null}
    app.post('/webhooks', (req, res) => {
      // Queue for async processing
      queue.add('process-webhook', req.body);

      // Respond immediately
      res.status(200).send('OK');
    });
    ```
  </Accordion>

  <Accordion title="Handle Duplicates" icon="copy">
    Use event IDs for idempotency:

    ```typescript theme={null}
    const processed = await redis.get(`webhook:${event.id}`);
    if (processed) return;

    await handleEvent(event);
    await redis.set(`webhook:${event.id}`, '1', 'EX', 86400);
    ```
  </Accordion>

  <Accordion title="Log Everything" icon="file-lines">
    Log all webhooks for debugging:

    ```typescript theme={null}
    console.log('Webhook received:', {
      id: event.id,
      type: event.type,
      timestamp: new Date().toISOString()
    });
    ```
  </Accordion>

  <Accordion title="Monitor Health" icon="heart-pulse">
    Track webhook success rates and latencies.
  </Accordion>
</AccordionGroup>

## Troubleshooting

### Common Issues

| Issue                | Solution                                        |
| -------------------- | ----------------------------------------------- |
| Invalid signature    | Check secret matches, verify raw body           |
| Missing events       | Confirm webhook is active and events subscribed |
| Timeouts             | Process async, return 200 quickly               |
| Duplicate processing | Implement idempotency with event IDs            |

### Check Delivery History

```bash theme={null}
curl -X GET "https://api.usmewe.com/v1/webhooks/{webhookId}/deliveries" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

<CardGroup cols={2}>
  <Card title="Webhooks API" icon="code" href="/developers/api-reference/webhooks">
    Full API reference
  </Card>

  <Card title="usmewe Pay" icon="credit-card" href="/guides/developers/integrate-usmewe-pay">
    Payment integration
  </Card>
</CardGroup>
