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

# Developer guide rate limits and webhooks

# Rhombus API Rate Limits & Webhooks — Developer Guide

This guide covers what you need to know to build reliable integrations with the Rhombus API, including how rate limiting works, how to handle throttled responses, and how to configure and consume webhooks.

***

## API Rate Limits

All API requests authenticated via **API key** or **OAuth token** are subject to rate limiting. Limits are enforced per credential and per organization.

### Authentication Methods

| Method      | Header                | Who It Applies To                        |
| ----------- | --------------------- | ---------------------------------------- |
| API Key     | `x-auth-apikey`       | Developer and Partner Developer accounts |
| OAuth Token | `x-auth-access-token` | OAuth-authorized applications            |

Both methods share the same rate limiting behavior described below.

### What Happens When You Hit the Limit

When your request is rate limited, the API returns:

```
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: text/plain

Too many api requests. Enhance your calm.
```

| Response Detail      | Value                                         |
| -------------------- | --------------------------------------------- |
| Status code          | `429`                                         |
| `Retry-After` header | `60` (seconds)                                |
| Body                 | `"Too many api requests. Enhance your calm."` |

### Handling a 429 Response

1. **Read the `Retry-After` header.** It tells you how many seconds to wait before retrying.
2. **Pause requests** for the duration specified (60 seconds).
3. **Retry your request** after the wait period.

Do **not** immediately retry on a 429 — repeated requests while rate limited will continue to be rejected and will not reset your limit window.

### Recommended Client-Side Strategy

**Exponential backoff with jitter** is the most resilient approach for any integration:

```
delay = min(base_delay * 2^attempt + random_jitter, max_delay)
```

| Parameter          | Recommended Value |
| ------------------ | ----------------- |
| Base delay         | 1 second          |
| Max delay          | 60 seconds        |
| Max retry attempts | 5-10              |
| Jitter             | Random 0-1 second |

**Example implementation (pseudocode):**

```
function callApi(request):
    for attempt in 0..max_retries:
        response = http.send(request)

        if response.status == 200:
            return response

        if response.status == 429:
            wait = parseRetryAfterHeader(response)  // use Retry-After when available
            sleep(wait)
            continue

        if response.status >= 500:
            delay = min(1 * 2^attempt + random(0, 1), 60)
            sleep(delay)
            continue

        // 4xx errors (other than 429) are not retryable
        throw ClientError(response)

    throw MaxRetriesExceeded()
```

### Key Points

* Rate limits are evaluated **per API key / OAuth token per organization**.
* The `Retry-After` header is always present on 429 responses — always prefer it over hardcoded delays.
* Server errors (5xx) are transient and safe to retry with backoff. Client errors (4xx other than 429) indicate a problem with your request and should not be retried.
* The rate limiting system is **fail-open** — if the rate limit service itself is unavailable, your request will be allowed through. Do not rely on this behavior; design your integration to respect limits.

***

## Webhooks

Webhooks allow your application to receive real-time event notifications via HTTP POST to a URL you configure. Webhook delivery, retry, and backoff are handled entirely server-side — your responsibility is to register your endpoint and process incoming payloads.

### Webhook Types

| Type           | Trigger                       | Use Case                                           |
| -------------- | ----------------------------- | -------------------------------------------------- |
| **Activity**   | Device events, alert activity | Motion detection, door access, face/vehicle alerts |
| **Diagnostic** | System health events          | Device offline, connectivity issues                |

### Configuration

Each webhook is identified by its **destination URL** and includes:

| Field             | Description                                                         |
| ----------------- | ------------------------------------------------------------------- |
| `webhookSecret`   | Shared secret for verifying payload signatures                      |
| `webhookDisabled` | Toggle to temporarily disable delivery without deleting the webhook |

You can register multiple webhooks per type. Each URL can be independently enabled or disabled.

### Webhook Lifecycle

```
Register URL + Secret  ─>  Events occur  ─>  Rhombus POSTs to your URL
                                                    │
                                         ┌──────────┴──────────┐
                                         │                     │
                                    2xx Success          Non-2xx Failure
                                    (delivered)          (server retries
                                                         with backoff)
```

### Delivery Behavior

The server manages delivery with built-in backoff:

* **Successful delivery (2xx):** Event is marked as delivered. A configurable backoff window prevents duplicate deliveries for the same event type.
* **Rate limited (429):** The server enters a backoff period for your webhook URL and retries later.
* **Gone (410):** Your webhook is marked as inactive. Re-register if your endpoint returns to service.
* **Other failures (non-2xx):** The server logs the error and retries according to its backoff schedule.

### Building a Reliable Webhook Receiver

**1. Respond quickly.** Return a `200 OK` as soon as you receive the payload. Process the event asynchronously.

```
POST /your-webhook-endpoint

# Good: acknowledge immediately, process later
return 200 OK
queue_for_processing(payload)

# Bad: process synchronously before responding
result = heavy_processing(payload)
return 200 OK
```

**2. Verify the signature.** Use the `webhookSecret` to validate that the payload came from Rhombus and has not been tampered with.

**3. Handle duplicates.** Webhook delivery is at-least-once. Your receiver should be idempotent — processing the same event twice should produce the same result. Use event identifiers to deduplicate.

**4. Return appropriate status codes.**

| Your Response   | What Rhombus Does                                               |
| --------------- | --------------------------------------------------------------- |
| `200-299`       | Marks as delivered; applies backoff window before next delivery |
| `410 Gone`      | Marks your webhook as inactive; stops sending                   |
| `429`           | Enters backoff; retries after a delay                           |
| Any other error | Retries with backoff                                            |

**5. Keep your endpoint available.** If your endpoint is consistently unreachable or returning errors, delivery attempts will continue with increasing backoff periods.

***

## Alert Backoff (Notification Throttling)

Alert notifications (distinct from webhooks) have a configurable **minimum interval** between consecutive alerts of the same type for a given entity. This prevents alert fatigue from high-frequency events like motion detection.

### Configurable Intervals

| Option                  | Seconds |
| ----------------------- | ------- |
| 1 Minute                | 60      |
| 2 Minutes               | 120     |
| **5 Minutes (default)** | 300     |
| 10 Minutes              | 600     |
| 20 Minutes              | 1200    |
| 30 Minutes              | 1800    |
| 1 Hour                  | 3600    |

This is set per policy and per activity type. During the backoff window, duplicate alerts for the same entity and activity are suppressed server-side. Alerts with **new identity information** (a different recognized face or license plate) bypass the backoff and are delivered immediately.

***

## Quick Reference

| Scenario                                   | What To Do                                                               |
| ------------------------------------------ | ------------------------------------------------------------------------ |
| Received `429` from the API                | Read `Retry-After` header, wait that many seconds, then retry            |
| Received `5xx` from the API                | Retry with exponential backoff (1s, 2s, 4s, ... up to 60s)               |
| Received `4xx` (not 429) from the API      | Do not retry — fix the request                                           |
| Webhook receiving duplicate events         | Deduplicate using event identifiers; return `200` promptly               |
| Webhook endpoint going offline temporarily | Rhombus retries with backoff; events will be redelivered when you return |
| Webhook endpoint permanently removed       | Return `410 Gone` so Rhombus stops delivery                              |
| Too many alerts for same event             | Configure alert backoff interval in policy settings (default 5 min)      |
