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

# Delivery and Retries

> Understanding webhook delivery mechanics and retry policies

Rise's webhook delivery system is designed for reliability and resilience. This guide explains how webhooks are delivered, what happens when deliveries fail, and how to optimize your endpoint for the best performance.

## How webhook delivery works

When an event occurs in your Rise account, our system immediately begins the delivery process:

<Steps>
  <Step title="Event triggered">
    A payment, deposit, or other action occurs in your Rise account
  </Step>

  <Step title="Webhook queued">
    Event is added to the delivery queue for each subscribed webhook endpoint
  </Step>

  <Step title="HTTP POST sent">
    Webhook payload is delivered to your endpoint via HTTP POST request
  </Step>

  <Step title="Response evaluated">
    Your endpoint's response determines whether delivery was successful
  </Step>

  <Step title="Success or retry">
    Successful deliveries are logged; failures trigger the retry mechanism
  </Step>
</Steps>

## Delivery expectations

### Response requirements

Your webhook endpoint should:

<CardGroup cols={2}>
  <Card title="Respond quickly" icon="stopwatch">
    Return a response within 10 seconds to avoid timeout
  </Card>

  <Card title="Return 2xx status" icon="check-circle">
    Any status code from 200-299 indicates successful delivery
  </Card>

  <Card title="Acknowledge receipt" icon="handshake">
    Send a simple response like `{"received": true}`
  </Card>

  <Card title="Handle duplicates" icon="copy">
    Process the same event multiple times safely (idempotency)
  </Card>
</CardGroup>

### What Rise considers successful

Rise considers a webhook delivery successful when:

* Your endpoint returns HTTP status **200-299**
* The response is received within **10 seconds**
* The connection completes without network errors

### What triggers a retry

Rise will retry webhook deliveries when:

* Your endpoint returns HTTP status **400-599**
* The request times out after **10 seconds**
* Network connection fails or is refused
* DNS resolution fails for your endpoint

## Retry policy

Rise implements an exponential backoff retry strategy to handle temporary failures gracefully.

### Retry schedule

When a delivery fails, Rise will retry according to this schedule:

<AccordionGroup>
  <Accordion title="First retry" icon="clock">
    **When**: After the initial failure
    **Wait time**: 1 minute (60 seconds)
    **Purpose**: Allow brief recovery time for temporary issues
  </Accordion>

  <Accordion title="Second retry" icon="hourglass">
    **When**: After first retry fails
    **Wait time**: 2 minutes (120 seconds)
    **Purpose**: Handle longer recovery periods
  </Accordion>

  <Accordion title="Final retry" icon="stopwatch">
    **When**: After second retry fails
    **Wait time**: 5 minutes (300 seconds)
    **Purpose**: Maximum retry attempt with extended delay
  </Accordion>
</AccordionGroup>

**Total retry period**: Up to approximately 8 minutes and 20 seconds from the original event
**Maximum attempts**: 4 total (initial + 3 retries)

<Note>
  **Retry timing**: Rise waits exactly **10 seconds** before initiating each retry attempt. This consistent delay applies to all retry attempts and helps ensure your endpoint has adequate time to recover from temporary issues.
</Note>

### Exponential backoff benefits

<CardGroup cols={2}>
  <Card title="Reduces server load" icon="server">
    Gives your endpoint time to recover from issues
  </Card>

  <Card title="Handles temporary issues" icon="wrench">
    Network glitches, brief downtime, or deployments
  </Card>

  <Card title="Prevents cascading failures" icon="shield">
    Avoids overwhelming already struggling endpoints
  </Card>

  <Card title="Maximizes delivery success" icon="bullseye">
    Multiple attempts significantly increase reliability
  </Card>
</CardGroup>

## Delivery status tracking

Every webhook delivery is tracked and recorded for monitoring and debugging.

### Delivery states

<Tabs>
  <Tab title="Pending">
    **Status**: Queued for delivery

    The webhook event has been created and is waiting in the delivery queue. This is the initial state before any delivery attempts.
  </Tab>

  <Tab title="Sending">
    **Status**: Currently being delivered

    Rise is actively attempting to deliver the webhook to your endpoint. This state is usually very brief.
  </Tab>

  <Tab title="Delivered">
    **Status**: Successfully received

    Your endpoint responded with a 2xx status code within the timeout period. The delivery is complete and successful.
  </Tab>

  <Tab title="Failed">
    **Status**: All retries exhausted

    All retry attempts have been exhausted and the webhook could not be delivered. Manual intervention may be required.
  </Tab>

  <Tab title="Retrying">
    **Status**: Scheduled for retry

    A delivery attempt failed but the webhook is scheduled to be retried according to the retry policy.
  </Tab>
</Tabs>

### Viewing delivery history

Access delivery history through your webhook details page in the Rise app:

<Steps>
  <Step title="Navigate to webhook settings">
    Go to the Developer section and click on Webhooks
  </Step>

  <Step title="Select your webhook">
    Click on the webhook you want to monitor
  </Step>

  <Step title="View delivery history">
    Click the "Delivery History" tab to see all delivery attempts
  </Step>

  <Step title="Filter and analyze">
    Use filters to focus on successful, failed, or pending deliveries
  </Step>
</Steps>

## Optimizing your endpoint

Follow these practices to ensure reliable webhook delivery:

### Response time optimization

<Tabs>
  <Tab title="Good practice">
    ```javascript theme={null}
    // Quick acknowledgment, async processing
    app.post('/webhooks', async (req, res) => {
      try {
        // Verify signature first with SDK
        const event = validator.validateEvent(req.body, req.headers['x-rise-signature']);
        
        // Acknowledge receipt immediately
        res.status(200).json({ received: true });
        
        // Process event asynchronously
        processWebhookAsync(event);
        
      } catch (error) {
        res.status(400).send('Verification failed');
      }
    });

    async function processWebhookAsync(event) {
      // Queue for background processing
      await jobQueue.add('process-webhook', event);
    }
    ```
  </Tab>

  <Tab title="Bad practice">
    ```javascript theme={null}
    // Slow processing blocks response
    app.post('/webhooks', async (req, res) => {
      try {
        const event = validator.validateEvent(req.body, req.headers['x-rise-signature']);
        
        // DON'T: Slow operations before responding
        await updateDatabase(event);           // 2-3 seconds
        await sendEmailNotification(event);    // 1-2 seconds
        await callExternalAPI(event);          // 3-5 seconds
        
        res.status(200).json({ received: true }); // Too late!
      } catch (error) {
        res.status(400).send('Error');
      }
    });
    ```
  </Tab>
</Tabs>

### Idempotency handling

Design your webhook handlers to safely process duplicate events:

```javascript theme={null}
function handlePaymentEvent(event) {
  const paymentId = event.payment.nanoid;
  
  // Check if already processed
  const existingRecord = database.findPayment(paymentId);
  if (existingRecord && existingRecord.webhookProcessed) {
    console.log(`Payment ${paymentId} already processed, skipping`);
    return; // Safe to ignore duplicate
  }
  
  // Process the payment
  database.updatePayment(paymentId, {
    status: event.payment.status,
    webhookProcessed: true,
    processedAt: new Date()
  });
  
  // Trigger business logic
  if (event.event_type === 'payment.sent') {
    fulfillOrder(event.payment.invoice_nanoid);
  }
}
```

### Error handling best practices

<CodeGroup>
  ```javascript Recommended approach theme={null}
  app.post('/webhooks', async (req, res) => {
    try {
      // Always verify first with SDK
      const event = validator.validateEvent(req.body, req.headers['x-rise-signature']);
      
      // Respond quickly
      res.status(200).json({ received: true });
      
      // Handle processing errors gracefully
      try {
        await processWebhook(event);
      } catch (processingError) {
        // Log error but don't fail the webhook
        console.error('Webhook processing error:', processingError);
        
        // Queue for retry or manual review
        await errorQueue.add('failed-webhook', {
          event: req.body,
          error: processingError.message,
          timestamp: new Date()
        });
      }
      
    } catch (verificationError) {
      // Only fail webhook for verification errors
      console.error('Webhook verification failed:', verificationError);
      res.status(400).send('Invalid signature');
    }
  });
  ```

  ```javascript What to avoid theme={null}
  app.post('/webhooks', async (req, res) => {
    try {
      const event = validator.validateEvent(req.body, req.headers['x-rise-signature']);
      
      // DON'T: Let processing errors fail the webhook
      await updateDatabase(event);    // If this fails...
      await sendEmail(event);         // ...webhook delivery fails
      await callAPI(event);           // ...and gets retried unnecessarily
      
      res.status(200).json({ received: true });
    } catch (error) {
      // This will cause unnecessary retries
      res.status(500).send('Processing failed');
    }
  });
  ```
</CodeGroup>

## Monitoring delivery performance

Track your webhook delivery metrics to maintain reliability:

### Key metrics to monitor

<CardGroup cols={2}>
  <Card title="Success rate" icon="percentage">
    **Target**: >99% first-attempt success rate

    Percentage of deliveries that succeed without requiring retries
  </Card>

  <Card title="Response time" icon="stopwatch">
    **Target**: \<2 seconds average

    How quickly your endpoint responds to webhook requests
  </Card>

  <Card title="Retry rate" icon="arrows-rotate">
    **Target**: \<5% of deliveries

    Percentage of deliveries requiring retry attempts
  </Card>

  <Card title="Final failure rate" icon="triangle-exclamation">
    **Target**: \<0.1% of deliveries

    Percentage of deliveries that ultimately fail after all retries
  </Card>
</CardGroup>

## Delivery limits and quotas

Rise implements reasonable limits to ensure system stability:

### Rate limits

<CardGroup cols={3}>
  <Card title="Delivery rate" icon="tachometer-alt">
    **Limit**: Reasonable per-endpoint rate

    Maximum webhook deliveries per second per endpoint
  </Card>

  <Card title="Burst allowance" icon="rocket">
    **Limit**: Short burst capacity

    Temporary higher rate for event spikes
  </Card>

  <Card title="Cooldown period" icon="snowflake">
    **Limit**: Recovery time

    Brief pause between burst periods
  </Card>
</CardGroup>

### Retry and storage limits

* **Maximum retries**: 3 attempts per webhook delivery
* **Retry window**: Approximately 8 minutes total retry period
* **Delivery history**: 30 days of delivery records stored
* **Event retention**: 7 days of event data available for redelivery

## What's next?

Now that you understand webhook delivery mechanics:

<CardGroup cols={2}>
  <Card title="Testing Strategies" icon="flask" href="/webhooks/implementation/testing">
    Learn how to test your delivery optimization and error handling
  </Card>

  <Card title="Monitoring Guide" icon="chart-line" href="/webhooks/operations/monitoring">
    Deep dive into delivery tracking and performance analysis
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/webhooks/operations/troubleshooting">
    Advanced troubleshooting techniques for delivery issues
  </Card>

  <Card title="Security Best Practices" icon="shield" href="/webhooks/getting-started/security">
    Review security considerations for reliable delivery
  </Card>
</CardGroup>

<Tip>
  **Performance tip**: The fastest webhook is one that responds immediately and processes asynchronously. Your users will thank you for the responsiveness, and Rise will thank you for the reliability.
</Tip>
